From 395ca2471cf165beefd2bb2def116850cb24f41c Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Wed, 8 Oct 2025 14:29:48 +0200 Subject: [PATCH 1/6] BridgeJS: Basic support for properties in protocols --- .../Sources/BridgeJSCore/ExportSwift.swift | 221 ++++++++++++++++-- .../Sources/BridgeJSLink/BridgeJSLink.swift | 60 +++++ .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 25 +- .../BridgeJSToolTests/Inputs/Protocol.swift | 2 + .../BridgeJSLinkTests/Protocol.Export.d.ts | 2 + .../BridgeJSLinkTests/Protocol.Export.js | 25 ++ .../ExportSwiftTests/Protocol.swift | 23 ++ .../Exporting-Swift-Protocols.md | 17 -- .../BridgeJSRuntimeTests/ExportAPITests.swift | 11 +- .../Generated/BridgeJS.ExportSwift.swift | 63 +++++ .../JavaScript/BridgeJS.ExportSwift.json | 41 +++- Tests/prelude.mjs | 29 ++- 12 files changed, 470 insertions(+), 49 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 9179a966..01a8343e 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -749,9 +749,8 @@ public class ExportSwift { case .topLevel: diagnose(node: node, message: "@JS var must be inside a @JS class or enum") return .skipChildren - case .protocolBody(_, _): - diagnose(node: node, message: "Properties are not supported in protocols") - return .skipChildren + case .protocolBody(let protocolName, let protocolKey): + return visitProtocolProperty(node: node, protocolName: protocolName, protocolKey: protocolKey) } // Process each binding (variable declaration) @@ -775,23 +774,8 @@ public class ExportSwift { // Check if property is readonly let isLet = node.bindingSpecifier.tokenKind == .keyword(.let) - let isGetterOnly = node.bindings.contains(where: { - switch $0.accessorBlock?.accessors { - case .accessors(let accessors): - // Has accessors - check if it only has a getter (no setter, willSet, or didSet) - return !accessors.contains(where: { accessor in - let tokenKind = accessor.accessorSpecifier.tokenKind - return tokenKind == .keyword(.set) || tokenKind == .keyword(.willSet) - || tokenKind == .keyword(.didSet) - }) - case .getter: - // Has only a getter block - return true - case nil: - // No accessor block - this is a stored property, not readonly - return false - } - }) + let isGetterOnly = node.bindings.contains(where: { self.hasOnlyGetter($0.accessorBlock) }) + let isReadonly = isLet || isGetterOnly let exportedProperty = ExportedProperty( @@ -997,6 +981,17 @@ public class ExportSwift { message: "Protocol visibility must be at least internal" ) + let protocolUniqueKey = makeKey(name: name, namespace: namespaceResult.namespace) + + exportedProtocolByName[protocolUniqueKey] = ExportedProtocol( + name: name, + methods: [], + properties: [], + namespace: namespaceResult.namespace + ) + + stateStack.push(state: .protocolBody(name: name, key: protocolUniqueKey)) + var methods: [ExportedFunction] = [] for member in node.memberBlock.members { if let funcDecl = member.decl.as(FunctionDeclSyntax.self) { @@ -1007,18 +1002,22 @@ public class ExportSwift { ) { methods.append(exportedFunction) } + } else if let varDecl = member.decl.as(VariableDeclSyntax.self) { + _ = visitProtocolProperty(node: varDecl, protocolName: name, protocolKey: protocolUniqueKey) } } let exportedProtocol = ExportedProtocol( name: name, methods: methods, + properties: exportedProtocolByName[protocolUniqueKey]?.properties ?? [], namespace: namespaceResult.namespace ) - - let protocolUniqueKey = makeKey(name: name, namespace: namespaceResult.namespace) + exportedProtocolByName[protocolUniqueKey] = exportedProtocol exportedProtocolNames.append(protocolUniqueKey) + + stateStack.pop() parent.exportedProtocolNameByKey[protocolUniqueKey] = name @@ -1075,6 +1074,89 @@ public class ExportSwift { ) } + private func visitProtocolProperty( + node: VariableDeclSyntax, + protocolName: String, + protocolKey: String + ) -> SyntaxVisitorContinueKind { + for binding in node.bindings { + guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self) else { + diagnose(node: binding.pattern, message: "Complex patterns not supported for protocol properties") + continue + } + + let propertyName = pattern.identifier.text + + guard let typeAnnotation = binding.typeAnnotation else { + diagnose(node: binding, message: "Protocol property must have explicit type annotation") + continue + } + + guard let propertyType = self.parent.lookupType(for: typeAnnotation.type) else { + diagnoseUnsupportedType(node: typeAnnotation.type, type: typeAnnotation.type.trimmedDescription) + continue + } + + if case .optional = propertyType { + diagnose( + node: typeAnnotation.type, + message: "Optional properties are not yet supported in protocols" + ) + continue + } + + guard let accessorBlock = binding.accessorBlock else { + diagnose( + node: binding, + message: "Protocol property must specify { get } or { get set }", + hint: "Add { get } for readonly or { get set } for readwrite property" + ) + continue + } + + let isReadonly = hasOnlyGetter(accessorBlock) + + let exportedProperty = ExportedProtocolProperty( + name: propertyName, + type: propertyType, + isReadonly: isReadonly + ) + + if var currentProtocol = exportedProtocolByName[protocolKey] { + var properties = currentProtocol.properties + properties.append(exportedProperty) + + currentProtocol = ExportedProtocol( + name: currentProtocol.name, + methods: currentProtocol.methods, + properties: properties, + namespace: currentProtocol.namespace + ) + exportedProtocolByName[protocolKey] = currentProtocol + } + } + + return .skipChildren + } + + private func hasOnlyGetter(_ accessorBlock: AccessorBlockSyntax?) -> Bool { + switch accessorBlock?.accessors { + case .accessors(let accessors): + // Has accessors - check if it only has a getter (no setter, willSet, or didSet) + return !accessors.contains(where: { accessor in + let tokenKind = accessor.accessorSpecifier.tokenKind + return tokenKind == .keyword(.set) || tokenKind == .keyword(.willSet) + || tokenKind == .keyword(.didSet) + }) + case .getter: + // Has only a getter block + return true + case nil: + // No accessor block - this is a stored property, not readonly + return false + } + } + override func visit(_ node: EnumCaseDeclSyntax) -> SyntaxVisitorContinueKind { guard case .enumBody(_, let enumKey) = stateStack.current else { return .visitChildren @@ -2179,11 +2261,24 @@ public class ExportSwift { methodDecls.append(methodImplementation) } + var propertyDecls: [DeclSyntax] = [] + + for property in proto.properties { + let propertyImpl = try renderProtocolProperty( + property: property, + protocolName: protocolName, + moduleName: moduleName + ) + propertyDecls.append(propertyImpl) + } + + let allDecls = (methodDecls + propertyDecls).map { $0.description }.joined(separator: "\n\n") + return """ struct \(raw: wrapperName): \(raw: protocolName), _BridgedSwiftProtocolWrapper { let jsObject: JSObject - \(raw: methodDecls.map { $0.description }.joined(separator: "\n\n")) + \(raw: allDecls) static func bridgeJSLiftParameter(_ value: Int32) -> Self { return \(raw: wrapperName)(jsObject: JSObject(id: UInt32(bitPattern: value))) @@ -2191,6 +2286,86 @@ public class ExportSwift { } """ } + + private func renderProtocolProperty( + property: ExportedProtocolProperty, + protocolName: String, + moduleName: String + ) throws -> DeclSyntax { + let getterAbiName = ABINameGenerator.generateABIName( + baseName: property.name, + namespace: nil, + staticContext: nil, + operation: "get", + className: protocolName + ) + let setterAbiName = ABINameGenerator.generateABIName( + baseName: property.name, + namespace: nil, + staticContext: nil, + operation: "set", + className: protocolName + ) + + // Generate getter + let liftingInfo = try property.type.liftingReturnInfo() + let getterReturnType: String + let getterCallCode: String + + if let abiType = liftingInfo.valueToLift { + getterReturnType = " -> \(abiType.swiftType)" + getterCallCode = """ + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return \(property.type.swiftType).bridgeJSLiftReturn(ret) + """ + } else { + // For String and other types that use tmpRetString + getterReturnType = "" + getterCallCode = """ + _extern_get(this: Int32(bitPattern: jsObject.id)) + return \(property.type.swiftType).bridgeJSLiftReturn() + """ + } + + if property.isReadonly { + // Readonly property - only getter + return """ + var \(raw: property.name): \(raw: property.type.swiftType) { + get { + @_extern(wasm, module: "\(raw: moduleName)", name: "\(raw: getterAbiName)") + func _extern_get(this: Int32)\(raw: getterReturnType) + \(raw: getterCallCode) + } + } + """ + } else { + // Readwrite property - getter and setter + let loweringInfo = try property.type.loweringParameterInfo() + assert( + loweringInfo.loweredParameters.count == 1, + "Protocol property setters must lower to a single WASM parameter" + ) + + let (paramName, wasmType) = loweringInfo.loweredParameters[0] + let setterParams = "this: Int32, \(paramName): \(wasmType.swiftType)" + let setterCallArgs = "this: Int32(bitPattern: jsObject.id), \(paramName): newValue.bridgeJSLowerParameter()" + + return """ + var \(raw: property.name): \(raw: property.type.swiftType) { + get { + @_extern(wasm, module: "\(raw: moduleName)", name: "\(raw: getterAbiName)") + func _extern_get(this: Int32)\(raw: getterReturnType) + \(raw: getterCallCode) + } + set { + @_extern(wasm, module: "\(raw: moduleName)", name: "\(raw: setterAbiName)") + func _extern_set(\(raw: setterParams)) + _extern_set(\(raw: setterCallArgs)) + } + } + """ + } + } } fileprivate enum Constants { diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 88f2af3d..1a182457 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -314,6 +314,13 @@ struct BridgeJSLink { } for proto in skeleton.protocols { + for property in proto.properties { + try renderProtocolProperty( + importObjectBuilder: importObjectBuilder, + protocol: proto, + property: property + ) + } for method in proto.methods { try renderProtocolMethod( importObjectBuilder: importObjectBuilder, @@ -607,6 +614,13 @@ struct BridgeJSLink { "\(method.name)\(renderTSSignature(parameters: method.parameters, returnType: method.returnType, effects: method.effects));" ) } + for property in proto.properties { + let propertySignature = + property.isReadonly + ? "readonly \(property.name): \(property.type.tsType);" + : "\(property.name): \(property.type.tsType);" + printer.write(propertySignature) + } } printer.write("}") printer.nextLine() @@ -2417,6 +2431,52 @@ extension BridgeJSLink { return (funcLines, []) } + func renderProtocolProperty( + importObjectBuilder: ImportObjectBuilder, + protocol: ExportedProtocol, + property: ExportedProtocolProperty + ) throws { + let getterAbiName = ABINameGenerator.generateABIName( + baseName: property.name, + namespace: nil, + staticContext: nil, + operation: "get", + className: `protocol`.name + ) + + let getterThunkBuilder = ImportedThunkBuilder() + getterThunkBuilder.liftSelf() + let returnExpr = try getterThunkBuilder.callPropertyGetter(name: property.name, returnType: property.type) + let getterLines = getterThunkBuilder.renderFunction( + name: getterAbiName, + returnExpr: returnExpr, + returnType: property.type + ) + importObjectBuilder.assignToImportObject(name: getterAbiName, function: getterLines) + + if !property.isReadonly { + let setterAbiName = ABINameGenerator.generateABIName( + baseName: property.name, + namespace: nil, + staticContext: nil, + operation: "set", + className: `protocol`.name + ) + let setterThunkBuilder = ImportedThunkBuilder() + setterThunkBuilder.liftSelf() + try setterThunkBuilder.liftParameter( + param: Parameter(label: nil, name: "value", type: property.type) + ) + setterThunkBuilder.callPropertySetter(name: property.name, returnType: property.type) + let setterLines = setterThunkBuilder.renderFunction( + name: setterAbiName, + returnExpr: nil, + returnType: .void + ) + importObjectBuilder.assignToImportObject(name: setterAbiName, function: setterLines) + } + } + func renderProtocolMethod( importObjectBuilder: ImportObjectBuilder, protocol: ExportedProtocol, diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 1a414b95..3cf34554 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -270,14 +270,37 @@ public enum EnumType: String, Codable, Sendable { // MARK: - Exported Skeleton +public struct ExportedProtocolProperty: Codable, Equatable, Sendable { + public let name: String + public let type: BridgeType + public let isReadonly: Bool + + public init( + name: String, + type: BridgeType, + isReadonly: Bool + ) { + self.name = name + self.type = type + self.isReadonly = isReadonly + } +} + public struct ExportedProtocol: Codable, Equatable { public let name: String public let methods: [ExportedFunction] + public let properties: [ExportedProtocolProperty] public let namespace: [String]? - public init(name: String, methods: [ExportedFunction], namespace: [String]? = nil) { + public init( + name: String, + methods: [ExportedFunction], + properties: [ExportedProtocolProperty] = [], + namespace: [String]? = nil + ) { self.name = name self.methods = methods + self.properties = properties self.namespace = namespace } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift index f0213369..54ca6abf 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift @@ -1,6 +1,8 @@ import JavaScriptKit @JS protocol MyViewControllerDelegate { + var eventCount: Int { get set } + var delegateName: String { get } func onSomethingHappened() func onValueChanged(_ value: String) func onCountUpdated(count: Int) -> Bool diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts index 0f5d0fb2..a6d1125e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts @@ -10,6 +10,8 @@ export interface MyViewControllerDelegate { onCountUpdated(count: number): boolean; onLabelUpdated(prefix: string, suffix: string): void; isCountEven(): boolean; + eventCount: number; + readonly delegateName: string; } /// Represents a Swift heap object like a class instance or an actor instance. diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js index 142c1cf0..847787d5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js @@ -147,6 +147,31 @@ export async function createInstantiator(options, swift) { return swift.memory.retain(obj); }; const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; + TestModule["bjs_MyViewControllerDelegate_eventCount_get"] = function bjs_MyViewControllerDelegate_eventCount_get(self) { + try { + let ret = swift.memory.getObject(self).eventCount; + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_MyViewControllerDelegate_eventCount_get"] = function bjs_MyViewControllerDelegate_eventCount_get(self, value) { + try { + swift.memory.getObject(self).eventCount = value; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_delegateName_get"] = function bjs_MyViewControllerDelegate_delegateName_get(self) { + try { + let ret = swift.memory.getObject(self).delegateName; + tmpRetBytes = textEncoder.encode(ret); + return tmpRetBytes.length; + } catch (error) { + setException(error); + } + } TestModule["bjs_MyViewControllerDelegate_onSomethingHappened"] = function bjs_MyViewControllerDelegate_onSomethingHappened(self) { try { swift.memory.getObject(self).onSomethingHappened(); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift index 6ac515c7..0e530467 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift @@ -41,6 +41,29 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto return Bool.bridgeJSLiftReturn(ret) } + var eventCount: Int { + get { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_eventCount_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Int.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_eventCount_set") + func _extern_set(this: Int32, value: Int32) + _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + } + } + + var delegateName: String { + get { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_delegateName_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return String.bridgeJSLiftReturn(ret) + } + } + static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyMyViewControllerDelegate(jsObject: JSObject(id: UInt32(bitPattern: value))) } diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md index 802ff3ae..8e1aa8a9 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md @@ -190,20 +190,3 @@ When you pass a JavaScript object implementing a protocol to Swift: | Protocol inheritance | ❌ | | Protocol composition: `Protocol1 & Protocol2` | ❌ | | Generics | ❌ | - -### Type Support for Protocol Method Parameters and Return Types - -Protocol method parameters and return values have more limited type support compared to regular exported Swift functions and classes. - -**Supported Types:** -- Primitives: `Bool`, `Int`, `Float`, `Double` -- `String` -- `JSObject` - -**Not Supported:** -- `@JS class` types -- `@JS enum` types (case, raw value, or associated value) -- `@JS protocol` types -- Optional types: `Int?`, `String?`, etc. - -> Note: For regular `@JS func` and `@JS class` exports (not within protocols), all these types including optionals, enums, and classes are fully supported. See and for more information. diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index b6255a4e..b49dca59 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -860,6 +860,8 @@ enum APIOptionalResult { // MARK: - Protocol Tests @JS protocol Counter { + var count: Int { get set } + var name: String { get } func increment(by amount: Int) func getValue() -> Int func setLabelElements(_ labelPrefix: String, _ labelSuffix: String) @@ -912,17 +914,18 @@ enum APIOptionalResult { } @JS class SwiftCounter: Counter { - private var value: Int = 0 + @JS var count: Int = 0 + @JS let name: String = "SwiftCounter" private var label: String = "" @JS init() {} @JS func increment(by amount: Int) { - value += amount + count += amount } @JS func getValue() -> Int { - return value + return count } @JS func setLabelElements(_ labelPrefix: String, _ labelSuffix: String) { @@ -934,7 +937,7 @@ enum APIOptionalResult { } @JS func isEven() -> Bool { - return value % 2 == 0 + return count % 2 == 0 } } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift index 1e22c2b0..3ee75a18 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift @@ -19,7 +19,11 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_getValue") func _extern_getValue(this: Int32) -> Int32 let ret = _extern_getValue(this: Int32(bitPattern: jsObject.id)) +<<<<<<< HEAD return Int.bridgeJSLiftReturn(ret) +======= + return Int.bridgeJSLiftReturn(ret) +>>>>>>> f19c8b06 (WIP: Initial protocol support) } func setLabelElements(_ labelPrefix: String, _ labelSuffix: String) { @@ -32,7 +36,11 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_getLabel") func _extern_getLabel(this: Int32) -> Int32 let ret = _extern_getLabel(this: Int32(bitPattern: jsObject.id)) +<<<<<<< HEAD return String.bridgeJSLiftReturn(ret) +======= + return String.bridgeJSLiftReturn(ret) +>>>>>>> f19c8b06 (WIP: Initial protocol support) } func isEven() -> Bool { @@ -42,6 +50,29 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { return Bool.bridgeJSLiftReturn(ret) } + var count: Int { + get { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_count_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Int.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_count_get") + func _extern_set(this: Int32, value: Int32) + _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + } + } + + var name: String { + get { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_name_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return String.bridgeJSLiftReturn(ret) + } + } + static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyCounter(jsObject: JSObject(id: UInt32(bitPattern: value))) } @@ -3509,6 +3540,38 @@ public func _bjs_SwiftCounter_isEven(_self: UnsafeMutableRawPointer) -> Int32 { #endif } +@_expose(wasm, "bjs_SwiftCounter_count_get") +@_cdecl("bjs_SwiftCounter_count_get") +public func _bjs_SwiftCounter_count_get(_self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = SwiftCounter.bridgeJSLiftParameter(_self).count + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftCounter_count_set") +@_cdecl("bjs_SwiftCounter_count_set") +public func _bjs_SwiftCounter_count_set(_self: UnsafeMutableRawPointer, value: Int32) -> Void { + #if arch(wasm32) + SwiftCounter.bridgeJSLiftParameter(_self).count = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftCounter_name_get") +@_cdecl("bjs_SwiftCounter_name_get") +public func _bjs_SwiftCounter_name_get(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftCounter.bridgeJSLiftParameter(_self).name + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_SwiftCounter_deinit") @_cdecl("bjs_SwiftCounter_deinit") public func _bjs_SwiftCounter_deinit(pointer: UnsafeMutableRawPointer) { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json index a6be6754..49afbd69 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json @@ -1505,7 +1505,26 @@ ], "name" : "SwiftCounter", "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "count", + "type" : { + "int" : { + } + } + }, + { + "isReadonly" : true, + "isStatic" : false, + "name" : "name", + "type" : { + "string" : { + + } + } + } ], "swiftCallName" : "SwiftCounter" } @@ -5896,7 +5915,27 @@ } } ], - "name" : "Counter" + "name" : "Counter", + "properties" : [ + { + "isReadonly" : false, + "name" : "count", + "type" : { + "int" : { + + } + } + }, + { + "isReadonly" : true, + "name" : "name", + "type" : { + "string" : { + + } + } + } + ] } ] } \ No newline at end of file diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index e2d0c980..ab3f4477 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -812,7 +812,9 @@ function testProtocolSupport(exports) { let counterValue = 0; let counterLabel = ""; const jsCounter = { - increment(amount) { counterValue += amount; }, + count: 0, + name: "JSCounter", + increment(amount) { counterValue += amount; this.count += amount; }, getValue() { return counterValue; }, setLabelElements(labelPrefix, labelSuffix) { counterLabel = labelPrefix + labelSuffix; }, getLabel() { return counterLabel; }, @@ -820,8 +822,13 @@ function testProtocolSupport(exports) { }; const manager = new exports.CounterManager(jsCounter); + + assert.equal(jsCounter.count, 0); + assert.equal(jsCounter.name, "JSCounter"); + manager.incrementByAmount(4); assert.equal(manager.getCurrentValue(), 4); + assert.equal(jsCounter.count, 4); manager.setCounterLabel("Test", "Label"); assert.equal(manager.getCounterLabel(), "TestLabel"); @@ -839,21 +846,33 @@ function testProtocolSupport(exports) { const swiftCounter = new exports.SwiftCounter(); const swiftManager = new exports.CounterManager(swiftCounter); + assert.equal(swiftCounter.count, 0); + assert.equal(swiftCounter.name, "SwiftCounter"); + swiftManager.incrementByAmount(10); assert.equal(swiftManager.getCurrentValue(), 10); + assert.equal(swiftCounter.count, 10); swiftManager.setCounterLabel("Swift", "Label"); assert.equal(swiftManager.getCounterLabel(), "SwiftLabel"); swiftCounter.increment(5); assert.equal(swiftCounter.getValue(), 15); + assert.equal(swiftCounter.count, 15); + + swiftCounter.count = 100; + assert.equal(swiftCounter.count, 100); + assert.equal(swiftCounter.getValue(), 100); + swiftManager.release(); swiftCounter.release(); let optionalCounterValue = 100; let optionalCounterLabel = "optional"; const optionalCounter = { - increment(amount) { optionalCounterValue += amount; }, + count: 100, + name: "OptionalCounter", + increment(amount) { optionalCounterValue += amount; this.count += amount; }, getValue() { return optionalCounterValue; }, setLabelElements(labelPrefix, labelSuffix) { optionalCounterLabel = labelPrefix + labelSuffix; }, getLabel() { return optionalCounterLabel; }, @@ -863,7 +882,9 @@ function testProtocolSupport(exports) { let mainCounterValue = 0; let mainCounterLabel = "main"; const mainCounter = { - increment(amount) { mainCounterValue += amount; }, + count: 0, + name: "MainCounter", + increment(amount) { mainCounterValue += amount; this.count += amount; }, getValue() { return mainCounterValue; }, setLabelElements(labelPrefix, labelSuffix) { mainCounterLabel = labelPrefix + labelSuffix; }, getLabel() { return mainCounterLabel; }, @@ -902,6 +923,8 @@ function testProtocolSupport(exports) { assert.equal(managerWithOptional.hasBackup(), true); assert.equal(managerWithOptional.getBackupValue(), 1); + assert.equal(swiftBackupCounter.count, 1); + assert.equal(swiftBackupCounter.name, "SwiftCounter"); managerWithOptional.release(); swiftBackupCounter.release(); From 731a047d0c616c24cd3e92165bdc0876feb03b69 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Tue, 14 Oct 2025 17:39:46 +0200 Subject: [PATCH 2/6] BridgeJS: Naive implementation for swiftheapobject BridgeJS: Improve SwiftHeapObject handling in import side --- .../Sources/BridgeJSCore/ExportSwift.swift | 8 +- .../Sources/BridgeJSCore/ImportTS.swift | 32 +++- .../Sources/BridgeJSLink/BridgeJSLink.swift | 16 +- .../Sources/BridgeJSLink/JSGlueGen.swift | 47 ++++-- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 6 + .../BridgeJSToolTests/Inputs/Protocol.swift | 18 +++ .../BridgeJSLinkTests/Protocol.Export.d.ts | 10 ++ .../BridgeJSLinkTests/Protocol.Export.js | 46 +++++- .../ExportSwiftTests/Protocol.json | 143 +++++++++++++++++- .../ExportSwiftTests/Protocol.swift | 85 +++++++++++ .../JavaScriptKit/BridgeJSInstrincics.swift | 16 +- .../Exporting-Swift-Protocols.md | 67 +++++++- .../BridgeJSRuntimeTests/ExportAPITests.swift | 10 ++ .../Generated/BridgeJS.ExportSwift.swift | 38 ++++- .../JavaScript/BridgeJS.ExportSwift.json | 84 ++++++++++ Tests/prelude.mjs | 32 +++- 16 files changed, 614 insertions(+), 44 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 01a8343e..2d5f2d41 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -2213,7 +2213,7 @@ public class ExportSwift { var externParams: [String] = ["this: Int32"] for param in method.parameters { - let loweringInfo = try param.type.loweringParameterInfo() + let loweringInfo = try param.type.loweringParameterInfo(context: .protocolExport) assert( loweringInfo.loweredParameters.count == 1, "Protocol parameters must lower to a single WASM type" @@ -2239,7 +2239,7 @@ public class ExportSwift { """ } else { returnTypeStr = " -> \(method.returnType.swiftType)" - let liftingInfo = try method.returnType.liftingReturnInfo() + let liftingInfo = try method.returnType.liftingReturnInfo(context: .protocolExport) if let abiType = liftingInfo.valueToLift { externReturnType = " -> \(abiType.swiftType)" } else { @@ -2308,7 +2308,7 @@ public class ExportSwift { ) // Generate getter - let liftingInfo = try property.type.liftingReturnInfo() + let liftingInfo = try property.type.liftingReturnInfo(context: .protocolExport) let getterReturnType: String let getterCallCode: String @@ -2340,7 +2340,7 @@ public class ExportSwift { """ } else { // Readwrite property - getter and setter - let loweringInfo = try property.type.loweringParameterInfo() + let loweringInfo = try property.type.loweringParameterInfo(context: .protocolExport) assert( loweringInfo.loweredParameters.count == 1, "Protocol property setters must lower to a single WASM parameter" diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 64e89d66..ac8ab03e 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -424,7 +424,7 @@ extension BridgeType { static let void = LoweringParameterInfo(loweredParameters: []) } - func loweringParameterInfo() throws -> LoweringParameterInfo { + func loweringParameterInfo(context: BridgeContext = .importTS) throws -> LoweringParameterInfo { switch self { case .bool: return .bool case .int: return .int @@ -433,8 +433,18 @@ extension BridgeType { case .string: return .string case .jsObject: return .jsObject case .void: return .void - case .swiftHeapObject: - throw BridgeJSCoreError("swiftHeapObject is not supported in imported signatures") + case .swiftHeapObject(let className): + switch context { + case .importTS: + throw BridgeJSCoreError( + """ + swiftHeapObject '\(className)' is not supported in TypeScript imports. + Swift classes can only be used in @JS protocols where Swift owns the instance. + """ + ) + case .protocolExport: + return LoweringParameterInfo(loweredParameters: [("pointer", .pointer)]) + } case .swiftProtocol: throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum: @@ -456,7 +466,7 @@ extension BridgeType { static let void = LiftingReturnInfo(valueToLift: nil) } - func liftingReturnInfo() throws -> LiftingReturnInfo { + func liftingReturnInfo(context: BridgeContext = .importTS) throws -> LiftingReturnInfo { switch self { case .bool: return .bool case .int: return .int @@ -465,8 +475,18 @@ extension BridgeType { case .string: return .string case .jsObject: return .jsObject case .void: return .void - case .swiftHeapObject: - throw BridgeJSCoreError("swiftHeapObject is not supported in imported signatures") + case .swiftHeapObject(let className): + switch context { + case .importTS: + throw BridgeJSCoreError( + """ + swiftHeapObject '\(className)' cannot be returned from imported TypeScript functions. + JavaScript cannot create Swift heap objects. + """ + ) + case .protocolExport: + return LiftingReturnInfo(valueToLift: .pointer) + } case .swiftProtocol: throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum: diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 1a182457..9f85dbcf 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -1856,13 +1856,15 @@ extension BridgeJSLink { let body: CodeFragmentPrinter let scope: JSGlueVariableScope let cleanupCode: CodeFragmentPrinter + let context: BridgeContext var parameterNames: [String] = [] var parameterForwardings: [String] = [] - init() { + init(context: BridgeContext = .importTS) { self.body = CodeFragmentPrinter() self.scope = JSGlueVariableScope() self.cleanupCode = CodeFragmentPrinter() + self.context = context } func liftSelf() { @@ -1870,7 +1872,7 @@ extension BridgeJSLink { } func liftParameter(param: Parameter) throws { - let liftingFragment = try IntrinsicJSFragment.liftParameter(type: param.type) + let liftingFragment = try IntrinsicJSFragment.liftParameter(type: param.type, context: context) assert( liftingFragment.parameters.count >= 1, "Lifting fragment should have at least one parameter to lift" @@ -1927,7 +1929,7 @@ extension BridgeJSLink { } private func call(callExpr: String, returnType: BridgeType) throws -> String? { - let loweringFragment = try IntrinsicJSFragment.lowerReturn(type: returnType) + let loweringFragment = try IntrinsicJSFragment.lowerReturn(type: returnType, context: context) let returnExpr: String? if loweringFragment.parameters.count == 0 { body.write("\(callExpr);") @@ -1947,7 +1949,7 @@ extension BridgeJSLink { func callConstructor(name: String) throws -> String? { let call = "new imports.\(name)(\(parameterForwardings.joined(separator: ", ")))" let type: BridgeType = .jsObject(name) - let loweringFragment = try IntrinsicJSFragment.lowerReturn(type: type) + let loweringFragment = try IntrinsicJSFragment.lowerReturn(type: type, context: context) return try lowerReturnValue(returnType: type, returnExpr: call, loweringFragment: loweringFragment) } @@ -2444,7 +2446,7 @@ extension BridgeJSLink { className: `protocol`.name ) - let getterThunkBuilder = ImportedThunkBuilder() + let getterThunkBuilder = ImportedThunkBuilder(context: .protocolExport) getterThunkBuilder.liftSelf() let returnExpr = try getterThunkBuilder.callPropertyGetter(name: property.name, returnType: property.type) let getterLines = getterThunkBuilder.renderFunction( @@ -2462,7 +2464,7 @@ extension BridgeJSLink { operation: "set", className: `protocol`.name ) - let setterThunkBuilder = ImportedThunkBuilder() + let setterThunkBuilder = ImportedThunkBuilder(context: .protocolExport) setterThunkBuilder.liftSelf() try setterThunkBuilder.liftParameter( param: Parameter(label: nil, name: "value", type: property.type) @@ -2482,7 +2484,7 @@ extension BridgeJSLink { protocol: ExportedProtocol, method: ExportedFunction ) throws { - let thunkBuilder = ImportedThunkBuilder() + let thunkBuilder = ImportedThunkBuilder(context: .protocolExport) thunkBuilder.liftSelf() for param in method.parameters { try thunkBuilder.liftParameter(param: param) diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index ef431432..b7adcb67 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -219,6 +219,20 @@ struct IntrinsicJSFragment: Sendable { } ) } + static func swiftHeapObjectLiftParameter(_ name: String) -> IntrinsicJSFragment { + return IntrinsicJSFragment( + parameters: ["pointer"], + printCode: { arguments, scope, printer, cleanupCode in + return ["\(name).__construct(\(arguments[0]))"] + } + ) + } + static let swiftHeapObjectLowerReturn = IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, scope, printer, cleanupCode in + return ["\(arguments[0]).pointer"] + } + ) static func associatedEnumLowerParameter(enumBase: String) -> IntrinsicJSFragment { IntrinsicJSFragment( @@ -468,17 +482,23 @@ struct IntrinsicJSFragment: Sendable { // MARK: - ImportedJS /// Returns a fragment that lifts Wasm core values to JS values for parameters - static func liftParameter(type: BridgeType) throws -> IntrinsicJSFragment { + /// + /// - Parameters: + /// - type: The bridge type to lift + /// - context: The bridge context (defaults to .importTS for backward compatibility) + static func liftParameter(type: BridgeType, context: BridgeContext = .importTS) throws -> IntrinsicJSFragment { switch type { case .int, .float, .double: return .identity case .bool: return .boolLiftParameter case .string: return .stringLiftParameter case .jsObject: return .jsObjectLiftParameter case .swiftHeapObject(let name): - throw BridgeJSLinkError( - message: - "Swift heap objects are not supported to be passed as parameters to imported JS functions: \(name)" - ) + guard context == .protocolExport else { + throw BridgeJSLinkError( + message: "swiftHeapObject '\(name)' can only be used in protocol exports, not in \(context)" + ) + } + return .swiftHeapObjectLiftParameter(name) case .swiftProtocol: return .jsObjectLiftParameter case .void: throw BridgeJSLinkError( @@ -509,16 +529,23 @@ struct IntrinsicJSFragment: Sendable { } /// Returns a fragment that lowers a JS value to Wasm core values for return values - static func lowerReturn(type: BridgeType) throws -> IntrinsicJSFragment { + /// + /// - Parameters: + /// - type: The bridge type to lower + /// - context: The bridge context (defaults to .importTS for backward compatibility) + static func lowerReturn(type: BridgeType, context: BridgeContext = .importTS) throws -> IntrinsicJSFragment { switch type { case .int, .float, .double: return .identity case .bool: return .boolLowerReturn case .string: return .stringLowerReturn case .jsObject: return .jsObjectLowerReturn - case .swiftHeapObject: - throw BridgeJSLinkError( - message: "Swift heap objects are not supported to be returned from imported JS functions" - ) + case .swiftHeapObject(let name): + guard context == .protocolExport else { + throw BridgeJSLinkError( + message: "swiftHeapObject '\(name)' can only be used in protocol exports, not in \(context)" + ) + } + return .swiftHeapObjectLowerReturn case .swiftProtocol: return .jsObjectLowerReturn case .void: return .void case .optional(let wrappedType): diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 3cf34554..504cd68a 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -67,6 +67,12 @@ public struct ABINameGenerator { // MARK: - Types +/// Context for bridge operations that determines which types are valid +public enum BridgeContext: Sendable { + case importTS + case protocolExport +} + public enum BridgeType: Codable, Equatable, Sendable { case int, float, double, string, bool, jsObject(String?), swiftHeapObject(String), void indirect case optional(BridgeType) diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift index 54ca6abf..901b6433 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift @@ -1,5 +1,17 @@ import JavaScriptKit +@JS class Helper { + @JS var value: Int + + @JS init(value: Int) { + self.value = value + } + + @JS func increment() { + value += 1 + } +} + @JS protocol MyViewControllerDelegate { var eventCount: Int { get set } var delegateName: String { get } @@ -8,6 +20,8 @@ import JavaScriptKit func onCountUpdated(count: Int) -> Bool func onLabelUpdated(_ prefix: String, _ suffix: String) func isCountEven() -> Bool + func onHelperUpdated(_ helper: Helper) + func createHelper() -> Helper } @JS class MyViewController { @@ -40,4 +54,8 @@ import JavaScriptKit @JS func checkEvenCount() -> Bool { return delegate.isCountEven() } + + @JS func sendHelper(_ helper: Helper) { + delegate.onHelperUpdated(helper) + } } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts index a6d1125e..6ff2f6f8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts @@ -10,6 +10,8 @@ export interface MyViewControllerDelegate { onCountUpdated(count: number): boolean; onLabelUpdated(prefix: string, suffix: string): void; isCountEven(): boolean; + onHelperUpdated(helper: Helper): void; + createHelper(): Helper; eventCount: number; readonly delegateName: string; } @@ -21,16 +23,24 @@ export interface SwiftHeapObject { /// Note: Calling this method will release the heap object and it will no longer be accessible. release(): void; } +export interface Helper extends SwiftHeapObject { + increment(): void; + value: number; +} export interface MyViewController extends SwiftHeapObject { triggerEvent(): void; updateValue(value: string): void; updateCount(count: number): boolean; updateLabel(prefix: string, suffix: string): void; checkEvenCount(): boolean; + sendHelper(helper: Helper): void; delegate: MyViewControllerDelegate; secondDelegate: MyViewControllerDelegate | null; } export type Exports = { + Helper: { + new(value: number): Helper; + } MyViewController: { new(delegate: MyViewControllerDelegate): MyViewController; } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js index 847787d5..d49b9b8f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js @@ -142,6 +142,10 @@ export async function createInstantiator(options, swift) { if (!importObject["TestModule"]) { importObject["TestModule"] = {}; } + importObject["TestModule"]["bjs_Helper_wrap"] = function(pointer) { + const obj = Helper.__construct(pointer); + return swift.memory.retain(obj); + }; importObject["TestModule"]["bjs_MyViewController_wrap"] = function(pointer) { const obj = MyViewController.__construct(pointer); return swift.memory.retain(obj); @@ -156,7 +160,7 @@ export async function createInstantiator(options, swift) { return 0 } } - TestModule["bjs_MyViewControllerDelegate_eventCount_get"] = function bjs_MyViewControllerDelegate_eventCount_get(self, value) { + TestModule["bjs_MyViewControllerDelegate_eventCount_set"] = function bjs_MyViewControllerDelegate_eventCount_set(self, value) { try { swift.memory.getObject(self).eventCount = value; } catch (error) { @@ -217,6 +221,22 @@ export async function createInstantiator(options, swift) { return 0 } } + TestModule["bjs_MyViewControllerDelegate_onHelperUpdated"] = function bjs_MyViewControllerDelegate_onHelperUpdated(self, helper) { + try { + swift.memory.getObject(self).onHelperUpdated(Helper.__construct(helper)); + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_createHelper"] = function bjs_MyViewControllerDelegate_createHelper(self) { + try { + let ret = swift.memory.getObject(self).createHelper(); + return ret.pointer; + } catch (error) { + setException(error); + return 0 + } + } }, setInstance: (i) => { instance = i; @@ -248,6 +268,26 @@ export async function createInstantiator(options, swift) { this.deinit(this.pointer); } } + class Helper extends SwiftHeapObject { + static __construct(ptr) { + return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_Helper_deinit, Helper.prototype); + } + + constructor(value) { + const ret = instance.exports.bjs_Helper_init(value); + return Helper.__construct(ret); + } + increment() { + instance.exports.bjs_Helper_increment(this.pointer); + } + get value() { + const ret = instance.exports.bjs_Helper_value_get(this.pointer); + return ret; + } + set value(value) { + instance.exports.bjs_Helper_value_set(this.pointer, value); + } + } class MyViewController extends SwiftHeapObject { static __construct(ptr) { return SwiftHeapObject.__wrap(ptr, instance.exports.bjs_MyViewController_deinit, MyViewController.prototype); @@ -283,6 +323,9 @@ export async function createInstantiator(options, swift) { const ret = instance.exports.bjs_MyViewController_checkEvenCount(this.pointer); return ret !== 0; } + sendHelper(helper) { + instance.exports.bjs_MyViewController_sendHelper(this.pointer, helper.pointer); + } get delegate() { const ret = instance.exports.bjs_MyViewController_delegate_get(this.pointer); const ret1 = swift.memory.getObject(ret); @@ -304,6 +347,7 @@ export async function createInstantiator(options, swift) { } } return { + Helper, MyViewController, }; }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json index 77327c45..6d8a2545 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json @@ -1,5 +1,59 @@ { "classes" : [ + { + "constructor" : { + "abiName" : "bjs_Helper_init", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "parameters" : [ + { + "label" : "value", + "name" : "value", + "type" : { + "int" : { + + } + } + } + ] + }, + "methods" : [ + { + "abiName" : "bjs_Helper_increment", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "increment", + "parameters" : [ + + ], + "returnType" : { + "void" : { + + } + } + } + ], + "name" : "Helper", + "properties" : [ + { + "isReadonly" : false, + "isStatic" : false, + "name" : "value", + "type" : { + "int" : { + + } + } + } + ], + "swiftCallName" : "Helper" + }, { "constructor" : { "abiName" : "bjs_MyViewController_init", @@ -136,6 +190,31 @@ "returnType" : { "bool" : { + } + } + }, + { + "abiName" : "bjs_MyViewController_sendHelper", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "sendHelper", + "parameters" : [ + { + "label" : "_", + "name" : "helper", + "type" : { + "swiftHeapObject" : { + "_0" : "Helper" + } + } + } + ], + "returnType" : { + "void" : { + } } } @@ -297,9 +376,71 @@ } } + }, + { + "abiName" : "bjs_MyViewControllerDelegate_onHelperUpdated", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "onHelperUpdated", + "parameters" : [ + { + "label" : "_", + "name" : "helper", + "type" : { + "swiftHeapObject" : { + "_0" : "Helper" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_MyViewControllerDelegate_createHelper", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "createHelper", + "parameters" : [ + + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "Helper" + } + } } ], - "name" : "MyViewControllerDelegate" + "name" : "MyViewControllerDelegate", + "properties" : [ + { + "isReadonly" : false, + "name" : "eventCount", + "type" : { + "int" : { + + } + } + }, + { + "isReadonly" : true, + "name" : "delegateName", + "type" : { + "string" : { + + } + } + } + ] } ] } \ No newline at end of file diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift index 0e530467..dbb78e3f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift @@ -41,6 +41,19 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto return Bool.bridgeJSLiftReturn(ret) } + func onHelperUpdated(_ helper: Helper) { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_onHelperUpdated") + func _extern_onHelperUpdated(this: Int32, helper: UnsafeMutableRawPointer) + _extern_onHelperUpdated(this: Int32(bitPattern: jsObject.id), helper: helper.bridgeJSLowerParameter()) + } + + func createHelper() -> Helper { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_createHelper") + func _extern_createHelper(this: Int32) -> UnsafeMutableRawPointer + let ret = _extern_createHelper(this: Int32(bitPattern: jsObject.id)) + return Helper.bridgeJSLiftReturn(ret) + } + var eventCount: Int { get { @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_eventCount_get") @@ -69,6 +82,68 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto } } +@_expose(wasm, "bjs_Helper_init") +@_cdecl("bjs_Helper_init") +public func _bjs_Helper_init(value: Int32) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = Helper(value: Int.bridgeJSLiftParameter(value)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Helper_increment") +@_cdecl("bjs_Helper_increment") +public func _bjs_Helper_increment(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + Helper.bridgeJSLiftParameter(_self).increment() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Helper_value_get") +@_cdecl("bjs_Helper_value_get") +public func _bjs_Helper_value_get(_self: UnsafeMutableRawPointer) -> Int32 { + #if arch(wasm32) + let ret = Helper.bridgeJSLiftParameter(_self).value + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Helper_value_set") +@_cdecl("bjs_Helper_value_set") +public func _bjs_Helper_value_set(_self: UnsafeMutableRawPointer, value: Int32) -> Void { + #if arch(wasm32) + Helper.bridgeJSLiftParameter(_self).value = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_Helper_deinit") +@_cdecl("bjs_Helper_deinit") +public func _bjs_Helper_deinit(pointer: UnsafeMutableRawPointer) { + Unmanaged.fromOpaque(pointer).release() +} + +extension Helper: ConvertibleToJSValue, _BridgedSwiftHeapObject { + var jsValue: JSValue { + #if arch(wasm32) + @_extern(wasm, module: "TestModule", name: "bjs_Helper_wrap") + func _bjs_Helper_wrap(_: UnsafeMutableRawPointer) -> Int32 + #else + func _bjs_Helper_wrap(_: UnsafeMutableRawPointer) -> Int32 { + fatalError("Only available on WebAssembly") + } + #endif + return .object(JSObject(id: UInt32(bitPattern: _bjs_Helper_wrap(Unmanaged.passRetained(self).toOpaque())))) + } +} + @_expose(wasm, "bjs_MyViewController_init") @_cdecl("bjs_MyViewController_init") public func _bjs_MyViewController_init(delegate: Int32) -> UnsafeMutableRawPointer { @@ -132,6 +207,16 @@ public func _bjs_MyViewController_checkEvenCount(_self: UnsafeMutableRawPointer) #endif } +@_expose(wasm, "bjs_MyViewController_sendHelper") +@_cdecl("bjs_MyViewController_sendHelper") +public func _bjs_MyViewController_sendHelper(_self: UnsafeMutableRawPointer, helper: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + MyViewController.bridgeJSLiftParameter(_self).sendHelper(_: Helper.bridgeJSLiftParameter(helper)) + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_MyViewController_delegate_get") @_cdecl("bjs_MyViewController_delegate_get") public func _bjs_MyViewController_delegate_get(_self: UnsafeMutableRawPointer) -> Int32 { diff --git a/Sources/JavaScriptKit/BridgeJSInstrincics.swift b/Sources/JavaScriptKit/BridgeJSInstrincics.swift index 4742aa62..b3325775 100644 --- a/Sources/JavaScriptKit/BridgeJSInstrincics.swift +++ b/Sources/JavaScriptKit/BridgeJSInstrincics.swift @@ -268,14 +268,14 @@ public protocol _BridgedSwiftHeapObject: AnyObject {} extension _BridgedSwiftHeapObject { // MARK: ImportTS - @available(*, unavailable, message: "Swift heap objects are not supported to be passed to imported JS functions") - @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Void {} - @available( - *, - unavailable, - message: "Swift heap objects are not supported to be returned from imported JS functions" - ) - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ pointer: UnsafeMutableRawPointer) -> Void {} + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> UnsafeMutableRawPointer { + // For protocol parameters, we pass the unretained pointer since JS already has a reference + return Unmanaged.passUnretained(self).toOpaque() + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ pointer: UnsafeMutableRawPointer) -> Self { + // For protocol returns, take an unretained value since JS manages the lifetime + return Unmanaged.fromOpaque(pointer).takeUnretainedValue() + } // MARK: ExportSwift @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ pointer: UnsafeMutableRawPointer) -> Self { diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md index 8e1aa8a9..b70b5c02 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md @@ -21,6 +21,8 @@ Mark a Swift protocol with `@JS` to expose it: import JavaScriptKit @JS protocol Counter { + var count: Int { get set } + var name: String { get } func increment(by amount: Int) func reset() func getValue() -> Int @@ -41,6 +43,14 @@ import JavaScriptKit @JS func getCurrentValue() -> Int { return delegate.getValue() } + + @JS func getCounterName() -> String { + return delegate.name + } + + @JS func setCountValue(_ value: Int) { + delegate.count = value + } } ``` @@ -53,6 +63,7 @@ const { exports } = await init({}); // Implement the Counter protocol const counterImpl = { count: 0, + name: "JSCounter", increment(amount) { this.count += amount; }, @@ -68,12 +79,17 @@ const counterImpl = { const manager = new exports.CounterManager(counterImpl); manager.incrementTwice(); console.log(manager.getCurrentValue()); // 2 +console.log(manager.getCounterName()); // "JSCounter" +manager.setCountValue(10); +console.log(counterImpl.count); // 10 ``` The generated TypeScript interface: ```typescript export interface Counter { + count: number; + readonly name: string; increment(amount: number): void; reset(): void; getValue(): number; @@ -94,6 +110,27 @@ BridgeJS generates a Swift wrapper struct for each `@JS` protocol. This wrapper struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { let jsObject: JSObject + var count: Int { + get { + @_extern(wasm, module: "TestModule", name: "bjs_Counter_count_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Int.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "TestModule", name: "bjs_Counter_count_set") + func _extern_set(this: Int32, value: Int32) + _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + } + } + + var name: String { + @_extern(wasm, module: "TestModule", name: "bjs_Counter_name_get") + func _extern_get(this: Int32) + _extern_get(this: Int32(bitPattern: jsObject.id)) + return String.bridgeJSLiftReturn() + } + func increment(by amount: Int) { @_extern(wasm, module: "TestModule", name: "bjs_Counter_increment") func _extern_increment(this: Int32, amount: Int32) @@ -128,13 +165,16 @@ You can also implement protocols in Swift and use them from JavaScript: ```swift @JS protocol Counter { + var count: Int { get set } + var name: String { get } func increment(by amount: Int) func reset() func getValue() -> Int } final class SwiftCounter: Counter { - private var count = 0 + var count = 0 + let name = "SwiftCounter" func increment(by amount: Int) { count += amount @@ -158,9 +198,13 @@ From JavaScript: ```javascript const counter = exports.createCounter(); +console.log(counter.name); // "SwiftCounter" counter.increment(5); counter.increment(3); console.log(counter.getValue()); // 8 +console.log(counter.count); // 8 +counter.count = 100; +console.log(counter.getValue()); // 100 counter.reset(); console.log(counter.getValue()); // 0 ``` @@ -183,10 +227,27 @@ When you pass a JavaScript object implementing a protocol to Swift: | Method requirements with return values | ✅ | | Throwing method requirements: `func method() throws(JSException)` | ✅ | | Async method requirements: `func method() async` | ✅ | +| Property requirements: `var property: Type { get }` | ✅ | +| Property requirements: `var property: Type { get set }` | ✅ | | Optional protocol methods | ❌ | -| Property requirements: `var property: Type { get }` | ❌ | -| Property requirements: `var property: Type { get set }` | ❌ | | Associated types | ❌ | | Protocol inheritance | ❌ | | Protocol composition: `Protocol1 & Protocol2` | ❌ | | Generics | ❌ | + +### Type Support for Protocol Properties and Method Parameters + +Protocol properties and method parameters have more limited type support compared to regular exported Swift functions and classes. This is because protocols bridge Swift implementations to JavaScript objects using the TypeScript import mechanism. + +**Supported Types:** +- Primitives: `Bool`, `Int`, `Float`, `Double` +- `String` +- `JSObject` + +**Not Supported:** +- `@JS class` types +- `@JS enum` types (case, raw value, or associated value) +- `@JS protocol` types +- Optional types: `Int?`, `String?`, etc. + +> Note: For regular `@JS func` and `@JS class` exports (not within protocols), all these types including optionals, enums, and classes are fully supported. See and for more information. diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index b49dca59..1cdea545 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -867,6 +867,8 @@ enum APIOptionalResult { func setLabelElements(_ labelPrefix: String, _ labelSuffix: String) func getLabel() -> String func isEven() -> Bool + func processGreeter(_ greeter: Greeter) -> String + func createGreeter() -> Greeter } @JS class CounterManager { @@ -939,6 +941,14 @@ enum APIOptionalResult { @JS func isEven() -> Bool { return count % 2 == 0 } + + @JS func processGreeter(_ greeter: Greeter) -> String { + return "SwiftCounter processed: \(greeter.greet())" + } + + @JS func createGreeter() -> Greeter { + return Greeter(name: "CounterGreeter") + } } class ExportAPITests: XCTestCase { diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift index 3ee75a18..026c1f32 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift @@ -50,6 +50,20 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { return Bool.bridgeJSLiftReturn(ret) } + func processGreeter(_ greeter: Greeter) -> String { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_processGreeter") + func _extern_processGreeter(this: Int32, greeter: UnsafeMutableRawPointer) -> Int32 + let ret = _extern_processGreeter(this: Int32(bitPattern: jsObject.id), greeter: greeter.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(ret) + } + + func createGreeter() -> Greeter { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_createGreeter") + func _extern_createGreeter(this: Int32) -> UnsafeMutableRawPointer + let ret = _extern_createGreeter(this: Int32(bitPattern: jsObject.id)) + return Greeter.bridgeJSLiftReturn(ret) + } + var count: Int { get { @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_count_get") @@ -58,7 +72,7 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { return Int.bridgeJSLiftReturn(ret) } set { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_count_get") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_count_set") func _extern_set(this: Int32, value: Int32) _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) } @@ -3540,6 +3554,28 @@ public func _bjs_SwiftCounter_isEven(_self: UnsafeMutableRawPointer) -> Int32 { #endif } +@_expose(wasm, "bjs_SwiftCounter_processGreeter") +@_cdecl("bjs_SwiftCounter_processGreeter") +public func _bjs_SwiftCounter_processGreeter(_self: UnsafeMutableRawPointer, greeter: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftCounter.bridgeJSLiftParameter(_self).processGreeter(_: Greeter.bridgeJSLiftParameter(greeter)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftCounter_createGreeter") +@_cdecl("bjs_SwiftCounter_createGreeter") +public func _bjs_SwiftCounter_createGreeter(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = SwiftCounter.bridgeJSLiftParameter(_self).createGreeter() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_SwiftCounter_count_get") @_cdecl("bjs_SwiftCounter_count_get") public func _bjs_SwiftCounter_count_get(_self: UnsafeMutableRawPointer) -> Int32 { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json index 49afbd69..79b0884b 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json @@ -1501,6 +1501,48 @@ } } + }, + { + "abiName" : "bjs_SwiftCounter_processGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processGreeter", + "parameters" : [ + { + "label" : "_", + "name" : "greeter", + "type" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_SwiftCounter_createGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "createGreeter", + "parameters" : [ + + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } } ], "name" : "SwiftCounter", @@ -5913,6 +5955,48 @@ } } + }, + { + "abiName" : "bjs_Counter_processGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processGreeter", + "parameters" : [ + { + "label" : "_", + "name" : "greeter", + "type" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Counter_createGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "createGreeter", + "parameters" : [ + + ], + "returnType" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } } ], "name" : "Counter", diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index ab3f4477..f5bbc355 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -818,7 +818,9 @@ function testProtocolSupport(exports) { getValue() { return counterValue; }, setLabelElements(labelPrefix, labelSuffix) { counterLabel = labelPrefix + labelSuffix; }, getLabel() { return counterLabel; }, - isEven() { return counterValue % 2 === 0; } + isEven() { return counterValue % 2 === 0; }, + processGreeter(greeter) { return `JSCounter processed: ${greeter.greet()}`; }, + createGreeter() { return new exports.Greeter("JSCounterGreeter"); } }; const manager = new exports.CounterManager(jsCounter); @@ -864,6 +866,26 @@ function testProtocolSupport(exports) { assert.equal(swiftCounter.count, 100); assert.equal(swiftCounter.getValue(), 100); + const testGreeter = new exports.Greeter("TestUser"); + const jsResult = jsCounter.processGreeter(testGreeter); + assert.equal(jsResult, "JSCounter processed: Hello, TestUser!"); + + const swiftResult = swiftCounter.processGreeter(testGreeter); + assert.equal(swiftResult, "SwiftCounter processed: Hello, TestUser!"); + + // Test swiftHeapObject return from protocol methods + const jsCreatedGreeter = jsCounter.createGreeter(); + assert.equal(jsCreatedGreeter.name, "JSCounterGreeter"); + assert.equal(jsCreatedGreeter.greet(), "Hello, JSCounterGreeter!"); + jsCreatedGreeter.release(); + + const swiftCreatedGreeter = swiftCounter.createGreeter(); + assert.equal(swiftCreatedGreeter.name, "CounterGreeter"); + assert.equal(swiftCreatedGreeter.greet(), "Hello, CounterGreeter!"); + swiftCreatedGreeter.release(); + + testGreeter.release(); + swiftManager.release(); swiftCounter.release(); @@ -876,7 +898,9 @@ function testProtocolSupport(exports) { getValue() { return optionalCounterValue; }, setLabelElements(labelPrefix, labelSuffix) { optionalCounterLabel = labelPrefix + labelSuffix; }, getLabel() { return optionalCounterLabel; }, - isEven() { return optionalCounterValue % 2 === 0; } + isEven() { return optionalCounterValue % 2 === 0; }, + processGreeter(greeter) { return `OptionalCounter processed: ${greeter.greet()}`; }, + createGreeter() { return new exports.Greeter("OptionalCounterGreeter"); } }; let mainCounterValue = 0; @@ -888,7 +912,9 @@ function testProtocolSupport(exports) { getValue() { return mainCounterValue; }, setLabelElements(labelPrefix, labelSuffix) { mainCounterLabel = labelPrefix + labelSuffix; }, getLabel() { return mainCounterLabel; }, - isEven() { return mainCounterValue % 2 === 0; } + isEven() { return mainCounterValue % 2 === 0; }, + processGreeter(greeter) { return `MainCounter processed: ${greeter.greet()}`; }, + createGreeter() { return new exports.Greeter("MainCounterGreeter"); } }; const managerWithOptional = new exports.CounterManager(mainCounter); From d59368a35382da9bb8f1a42a0ad0a1d5206e62f3 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Wed, 15 Oct 2025 12:42:58 +0200 Subject: [PATCH 3/6] BridgeJS: Support for Optional for properties / method parameters / method return types in protocol --- .../Sources/BridgeJSCore/ExportSwift.swift | 74 ++++--- .../Sources/BridgeJSCore/ImportTS.swift | 23 +- .../Sources/BridgeJSLink/BridgeJSLink.swift | 3 +- .../Sources/BridgeJSLink/JSGlueGen.swift | 196 +++++++++++++++++- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 2 +- .../BridgeJSToolTests/Inputs/Protocol.swift | 9 +- .../BridgeJSLinkTests/Protocol.Export.d.ts | 3 + .../BridgeJSLinkTests/Protocol.Export.js | 44 ++++ .../ExportSwiftTests/Protocol.json | 63 ++++++ .../ExportSwiftTests/Protocol.swift | 27 +++ .../JavaScriptKit/BridgeJSInstrincics.swift | 49 +++-- .../Exporting-Swift-Protocols.md | 41 ++-- .../BridgeJSRuntimeTests/ExportAPITests.swift | 20 +- .../Generated/BridgeJS.ExportSwift.swift | 71 +++++++ .../JavaScript/BridgeJS.ExportSwift.json | 127 ++++++++++++ Tests/prelude.mjs | 44 +++- 16 files changed, 708 insertions(+), 88 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 2d5f2d41..526b2562 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -982,16 +982,16 @@ public class ExportSwift { ) let protocolUniqueKey = makeKey(name: name, namespace: namespaceResult.namespace) - + exportedProtocolByName[protocolUniqueKey] = ExportedProtocol( name: name, methods: [], properties: [], namespace: namespaceResult.namespace ) - + stateStack.push(state: .protocolBody(name: name, key: protocolUniqueKey)) - + var methods: [ExportedFunction] = [] for member in node.memberBlock.members { if let funcDecl = member.decl.as(FunctionDeclSyntax.self) { @@ -1013,10 +1013,10 @@ public class ExportSwift { properties: exportedProtocolByName[protocolUniqueKey]?.properties ?? [], namespace: namespaceResult.namespace ) - + exportedProtocolByName[protocolUniqueKey] = exportedProtocol exportedProtocolNames.append(protocolUniqueKey) - + stateStack.pop() parent.exportedProtocolNameByKey[protocolUniqueKey] = name @@ -1097,14 +1097,6 @@ public class ExportSwift { continue } - if case .optional = propertyType { - diagnose( - node: typeAnnotation.type, - message: "Optional properties are not yet supported in protocols" - ) - continue - } - guard let accessorBlock = binding.accessorBlock else { diagnose( node: binding, @@ -1125,7 +1117,7 @@ public class ExportSwift { if var currentProtocol = exportedProtocolByName[protocolKey] { var properties = currentProtocol.properties properties.append(exportedProperty) - + currentProtocol = ExportedProtocol( name: currentProtocol.name, methods: currentProtocol.methods, @@ -2240,15 +2232,34 @@ public class ExportSwift { } else { returnTypeStr = " -> \(method.returnType.swiftType)" let liftingInfo = try method.returnType.liftingReturnInfo(context: .protocolExport) - if let abiType = liftingInfo.valueToLift { + + if case .optional = method.returnType { + if let abiType = liftingInfo.valueToLift { + externReturnType = " -> \(abiType.swiftType)" + callCode = """ + let ret = _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) + return \(raw: method.returnType.swiftType).bridgeJSLiftReturn(ret) + """ + } else { + externReturnType = "" + callCode = """ + _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) + return \(raw: method.returnType.swiftType).bridgeJSLiftReturn() + """ + } + } else if let abiType = liftingInfo.valueToLift { externReturnType = " -> \(abiType.swiftType)" + callCode = """ + let ret = _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) + return \(raw: method.returnType.swiftType).bridgeJSLiftReturn(ret) + """ } else { externReturnType = "" + callCode = """ + _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) + return \(raw: method.returnType.swiftType).bridgeJSLiftReturn() + """ } - callCode = """ - let ret = _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) - return \(raw: method.returnType.swiftType).bridgeJSLiftReturn(ret) - """ } let methodImplementation: DeclSyntax = """ func \(raw: method.name)(\(raw: swiftParams.joined(separator: ", ")))\(raw: returnTypeStr) { @@ -2286,7 +2297,7 @@ public class ExportSwift { } """ } - + private func renderProtocolProperty( property: ExportedProtocolProperty, protocolName: String, @@ -2306,27 +2317,27 @@ public class ExportSwift { operation: "set", className: protocolName ) - + // Generate getter let liftingInfo = try property.type.liftingReturnInfo(context: .protocolExport) let getterReturnType: String let getterCallCode: String - + if let abiType = liftingInfo.valueToLift { getterReturnType = " -> \(abiType.swiftType)" getterCallCode = """ - let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) - return \(property.type.swiftType).bridgeJSLiftReturn(ret) - """ + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return \(property.type.swiftType).bridgeJSLiftReturn(ret) + """ } else { // For String and other types that use tmpRetString getterReturnType = "" getterCallCode = """ - _extern_get(this: Int32(bitPattern: jsObject.id)) - return \(property.type.swiftType).bridgeJSLiftReturn() - """ + _extern_get(this: Int32(bitPattern: jsObject.id)) + return \(property.type.swiftType).bridgeJSLiftReturn() + """ } - + if property.isReadonly { // Readonly property - only getter return """ @@ -2345,11 +2356,11 @@ public class ExportSwift { loweringInfo.loweredParameters.count == 1, "Protocol property setters must lower to a single WASM parameter" ) - + let (paramName, wasmType) = loweringInfo.loweredParameters[0] let setterParams = "this: Int32, \(paramName): \(wasmType.swiftType)" let setterCallArgs = "this: Int32(bitPattern: jsObject.id), \(paramName): newValue.bridgeJSLowerParameter()" - + return """ var \(raw: property.name): \(raw: property.type.swiftType) { get { @@ -2542,6 +2553,7 @@ extension BridgeType { throw BridgeJSCoreError("Namespace enums are not supported to pass as parameters") } } + } extension DeclModifierSyntax { diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index ac8ab03e..52ff813a 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -449,8 +449,13 @@ extension BridgeType { throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum: throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .optional: - throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") + case .optional(let wrappedType): + switch context { + case .importTS: + throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") + case .protocolExport: + return try wrappedType.loweringParameterInfo(context: context) + } } } @@ -492,7 +497,19 @@ extension BridgeType { case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum: throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") case .optional: - throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") + switch context { + case .importTS: + throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") + case .protocolExport: + // For Optional, return the length (or -1 for null) + if case .optional(.string) = self { + return .string + } + if case .optional(.swiftHeapObject) = self { + return LiftingReturnInfo(valueToLift: .pointer) + } + return LiftingReturnInfo(valueToLift: nil) + } } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 9f85dbcf..4445ddeb 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -1883,6 +1883,7 @@ extension BridgeJSLink { valuesToLift = [scope.variable(param.name)] } else { valuesToLift = liftingFragment.parameters.map { scope.variable(param.name + $0.capitalizedFirstLetter) } + parameterNames.append(contentsOf: valuesToLift) } let liftedValues = liftingFragment.printCode(valuesToLift, scope, body, cleanupCode) assert(liftedValues.count == 1, "Lifting fragment should produce exactly one value") @@ -2455,7 +2456,7 @@ extension BridgeJSLink { returnType: property.type ) importObjectBuilder.assignToImportObject(name: getterAbiName, function: getterLines) - + if !property.isReadonly { let setterAbiName = ABINameGenerator.generateABIName( baseName: property.name, diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index b7adcb67..1e92b09a 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -263,6 +263,70 @@ struct IntrinsicJSFragment: Sendable { ) } + static func optionalLiftParameter(wrappedType: BridgeType, context: BridgeContext) throws -> IntrinsicJSFragment { + return IntrinsicJSFragment( + parameters: ["isSome", "wrappedValue"], + printCode: { arguments, scope, printer, cleanupCode in + let isSome = arguments[0] + let wrappedValue = arguments[1] + + let resultExpr: String + switch wrappedType { + case .int, .float, .double, .caseEnum: + resultExpr = "\(isSome) ? \(wrappedValue) : null" + + case .bool: + resultExpr = "\(isSome) ? \(wrappedValue) !== 0 : null" + + case .string: + let objectLabel = scope.variable("obj") + printer.write("let \(objectLabel);") + printer.write("if (\(isSome)) {") + printer.indent { + printer.write( + "\(objectLabel) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue));" + ) + printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(wrappedValue));") + } + printer.write("}") + resultExpr = "\(isSome) ? \(objectLabel) : null" + + case .swiftHeapObject(let name): + resultExpr = "\(isSome) ? \(name).__construct(\(wrappedValue)) : null" + + case .jsObject: + resultExpr = + "\(isSome) ? \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue)) : null" + + case .rawValueEnum(_, let rawType): + switch rawType { + case .string: + let objectLabel = scope.variable("obj") + printer.write("let \(objectLabel);") + printer.write("if (\(isSome)) {") + printer.indent { + printer.write( + "\(objectLabel) = \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue));" + ) + printer.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(wrappedValue));") + } + printer.write("}") + resultExpr = "\(isSome) ? \(objectLabel) : null" + case .bool: + resultExpr = "\(isSome) ? \(wrappedValue) !== 0 : null" + default: + resultExpr = "\(isSome) ? \(wrappedValue) : null" + } + + default: + resultExpr = "\(isSome) ? \(wrappedValue) : null" + } + + return [resultExpr] + } + ) + } + static func optionalLowerParameter(wrappedType: BridgeType) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["value"], @@ -423,6 +487,114 @@ struct IntrinsicJSFragment: Sendable { ) } + static func optionalLowerReturn(wrappedType: BridgeType) throws -> IntrinsicJSFragment { + switch wrappedType { + case .bool, .int, .float, .double, .string, .swiftHeapObject, .jsObject, .swiftProtocol, .caseEnum, + .rawValueEnum: + break + case .void, .optional, .associatedValueEnum, .namespaceEnum: + throw BridgeJSLinkError(message: "Unsupported optional wrapped type for protocol export: \(wrappedType)") + } + + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, scope, printer, cleanupCode in + let value = arguments[0] + let isSomeVar = scope.variable("isSome") + + printer.write("const \(isSomeVar) = \(value) != null;") + + switch wrappedType { + case .bool: + printer.write( + "bjs[\"swift_js_return_optional_bool\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) ? 1 : 0) : 0);" + ) + case .int, .caseEnum: + printer.write( + "bjs[\"swift_js_return_optional_int\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) | 0) : 0);" + ) + case .float: + printer.write( + "bjs[\"swift_js_return_optional_float\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? Math.fround(\(value)) : 0.0);" + ) + case .double: + printer.write( + "bjs[\"swift_js_return_optional_double\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? \(value) : 0.0);" + ) + case .string: + let bytesVar = scope.variable("bytes") + printer.write("if (\(isSomeVar)) {") + printer.indent { + printer.write( + "const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));" + ) + printer.write("bjs[\"swift_js_return_optional_string\"](1, \(bytesVar), \(bytesVar).length);") + printer.write("return \(bytesVar).length;") + } + printer.write("} else {") + printer.indent { + printer.write("bjs[\"swift_js_return_optional_string\"](0, 0, 0);") + printer.write("return -1;") + } + printer.write("}") + + case .swiftHeapObject: + printer.write("return \(isSomeVar) ? \(value).pointer : 0;") + case .jsObject, .swiftProtocol: + let idVar = scope.variable("id") + printer.write("let \(idVar) = 0;") + printer.write("if (\(isSomeVar)) {") + printer.indent { + printer.write("\(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));") + } + printer.write("}") + printer.write("bjs[\"swift_js_return_optional_object\"](\(isSomeVar) ? 1 : 0, \(idVar));") + case .rawValueEnum(_, let rawType): + switch rawType { + case .string: + let bytesVar = scope.variable("bytes") + printer.write("if (\(isSomeVar)) {") + printer.indent { + printer.write( + "const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));" + ) + printer.write( + "bjs[\"swift_js_return_optional_string\"](1, \(bytesVar), \(bytesVar).length);" + ) + printer.write("return \(bytesVar).length;") + } + printer.write("} else {") + printer.indent { + printer.write("bjs[\"swift_js_return_optional_string\"](0, 0, 0);") + printer.write("return -1;") + } + printer.write("}") + case .bool: + printer.write( + "bjs[\"swift_js_return_optional_bool\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) ? 1 : 0) : 0);" + ) + case .float: + printer.write( + "bjs[\"swift_js_return_optional_float\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? Math.fround(\(value)) : 0.0);" + ) + case .double: + printer.write( + "bjs[\"swift_js_return_optional_double\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? \(value) : 0.0);" + ) + default: + printer.write( + "bjs[\"swift_js_return_optional_int\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) | 0) : 0);" + ) + } + default: + () + } + + return [] + } + ) + } + // MARK: - ExportSwift /// Returns a fragment that lowers a JS value to Wasm core values for parameters @@ -505,9 +677,15 @@ struct IntrinsicJSFragment: Sendable { message: "Void can't appear in parameters of imported JS functions" ) case .optional(let wrappedType): - throw BridgeJSLinkError( - message: "Optional types are not supported for imported JS functions: \(wrappedType)" - ) + switch context { + case .importTS: + throw BridgeJSLinkError( + message: "Optional types are not supported for imported JS functions: \(wrappedType)" + ) + case .protocolExport: + // Protocol exports support Optional - use existing optionalLiftParameter fragment + return try .optionalLiftParameter(wrappedType: wrappedType, context: context) + } case .caseEnum: return .identity case .rawValueEnum(_, let rawType): switch rawType { @@ -549,9 +727,15 @@ struct IntrinsicJSFragment: Sendable { case .swiftProtocol: return .jsObjectLowerReturn case .void: return .void case .optional(let wrappedType): - throw BridgeJSLinkError( - message: "Optional types are not supported for imported JS functions: \(wrappedType)" - ) + switch context { + case .importTS: + throw BridgeJSLinkError( + message: "Optional types are not supported for imported JS functions: \(wrappedType)" + ) + case .protocolExport: + // Protocol exports support Optional - use side channel approach for return values + return try .optionalLowerReturn(wrappedType: wrappedType) + } case .caseEnum: return .identity case .rawValueEnum(_, let rawType): switch rawType { diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 504cd68a..233e7903 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -280,7 +280,7 @@ public struct ExportedProtocolProperty: Codable, Equatable, Sendable { public let name: String public let type: BridgeType public let isReadonly: Bool - + public init( name: String, type: BridgeType, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift index 901b6433..63a6d9ac 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift @@ -2,11 +2,11 @@ import JavaScriptKit @JS class Helper { @JS var value: Int - + @JS init(value: Int) { self.value = value } - + @JS func increment() { value += 1 } @@ -15,6 +15,7 @@ import JavaScriptKit @JS protocol MyViewControllerDelegate { var eventCount: Int { get set } var delegateName: String { get } + var optionalName: String? { get set } func onSomethingHappened() func onValueChanged(_ value: String) func onCountUpdated(count: Int) -> Bool @@ -22,6 +23,8 @@ import JavaScriptKit func isCountEven() -> Bool func onHelperUpdated(_ helper: Helper) func createHelper() -> Helper + func onOptionalHelperUpdated(_ helper: Helper?) + func createOptionalHelper() -> Helper? } @JS class MyViewController { @@ -54,7 +57,7 @@ import JavaScriptKit @JS func checkEvenCount() -> Bool { return delegate.isCountEven() } - + @JS func sendHelper(_ helper: Helper) { delegate.onHelperUpdated(helper) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts index 6ff2f6f8..2d489979 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts @@ -12,8 +12,11 @@ export interface MyViewControllerDelegate { isCountEven(): boolean; onHelperUpdated(helper: Helper): void; createHelper(): Helper; + onOptionalHelperUpdated(helper: Helper | null): void; + createOptionalHelper(): Helper | null; eventCount: number; readonly delegateName: string; + optionalName: string | null; } /// Represents a Swift heap object like a class instance or an actor instance. diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js index d49b9b8f..1d9329c3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js @@ -176,6 +176,34 @@ export async function createInstantiator(options, swift) { setException(error); } } + TestModule["bjs_MyViewControllerDelegate_optionalName_get"] = function bjs_MyViewControllerDelegate_optionalName_get(self) { + try { + let ret = swift.memory.getObject(self).optionalName; + const isSome = ret != null; + if (isSome) { + const bytes = textEncoder.encode(ret); + bjs["swift_js_return_optional_string"](1, bytes, bytes.length); + return bytes.length; + } else { + bjs["swift_js_return_optional_string"](0, 0, 0); + return -1; + } + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_optionalName_set"] = function bjs_MyViewControllerDelegate_optionalName_set(self, valueIsSome, valueWrappedValue) { + try { + let obj; + if (valueIsSome) { + obj = swift.memory.getObject(valueWrappedValue); + swift.memory.release(valueWrappedValue); + } + swift.memory.getObject(self).optionalName = valueIsSome ? obj : null; + } catch (error) { + setException(error); + } + } TestModule["bjs_MyViewControllerDelegate_onSomethingHappened"] = function bjs_MyViewControllerDelegate_onSomethingHappened(self) { try { swift.memory.getObject(self).onSomethingHappened(); @@ -237,6 +265,22 @@ export async function createInstantiator(options, swift) { return 0 } } + TestModule["bjs_MyViewControllerDelegate_onOptionalHelperUpdated"] = function bjs_MyViewControllerDelegate_onOptionalHelperUpdated(self, helperIsSome, helperWrappedValue) { + try { + swift.memory.getObject(self).onOptionalHelperUpdated(helperIsSome ? Helper.__construct(helperWrappedValue) : null); + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_createOptionalHelper"] = function bjs_MyViewControllerDelegate_createOptionalHelper(self) { + try { + let ret = swift.memory.getObject(self).createOptionalHelper(); + const isSome = ret != null; + return isSome ? ret.pointer : 0; + } catch (error) { + setException(error); + } + } }, setInstance: (i) => { instance = i; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json index 6d8a2545..30abfc91 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json @@ -418,6 +418,56 @@ "_0" : "Helper" } } + }, + { + "abiName" : "bjs_MyViewControllerDelegate_onOptionalHelperUpdated", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "onOptionalHelperUpdated", + "parameters" : [ + { + "label" : "_", + "name" : "helper", + "type" : { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Helper" + } + } + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_MyViewControllerDelegate_createOptionalHelper", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "createOptionalHelper", + "parameters" : [ + + ], + "returnType" : { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Helper" + } + } + } + } } ], "name" : "MyViewControllerDelegate", @@ -439,6 +489,19 @@ } } + }, + { + "isReadonly" : false, + "name" : "optionalName", + "type" : { + "optional" : { + "_0" : { + "string" : { + + } + } + } + } } ] } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift index dbb78e3f..ea1d71ea 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift @@ -54,6 +54,19 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto return Helper.bridgeJSLiftReturn(ret) } + func onOptionalHelperUpdated(_ helper: Optional) { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_onOptionalHelperUpdated") + func _extern_onOptionalHelperUpdated(this: Int32, helper: UnsafeMutableRawPointer) + _extern_onOptionalHelperUpdated(this: Int32(bitPattern: jsObject.id), helper: helper.bridgeJSLowerParameter()) + } + + func createOptionalHelper() -> Optional { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_createOptionalHelper") + func _extern_createOptionalHelper(this: Int32) -> UnsafeMutableRawPointer + let ret = _extern_createOptionalHelper(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturn(ret) + } + var eventCount: Int { get { @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_eventCount_get") @@ -77,6 +90,20 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto } } + var optionalName: Optional { + get { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_optionalName_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_optionalName_set") + func _extern_set(this: Int32, value: Int32) + _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + } + } + static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyMyViewControllerDelegate(jsObject: JSObject(id: UInt32(bitPattern: value))) } diff --git a/Sources/JavaScriptKit/BridgeJSInstrincics.swift b/Sources/JavaScriptKit/BridgeJSInstrincics.swift index b3325775..5a8f7f01 100644 --- a/Sources/JavaScriptKit/BridgeJSInstrincics.swift +++ b/Sources/JavaScriptKit/BridgeJSInstrincics.swift @@ -538,11 +538,23 @@ extension Optional where Wrapped == Int { extension Optional where Wrapped == String { // MARK: ImportTS - @available(*, unavailable, message: "Optional String type is not supported to be passed to imported JS functions") - @_spi(BridgeJS) public func bridgeJSLowerParameter() -> Void {} + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + switch consume self { + case .none: + return 0 + case .some(let value): + return value.bridgeJSLowerParameter() + } + } - @available(*, unavailable, message: "Optional String type is not supported to be passed to imported JS functions") - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32) -> String? { return nil } + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ length: Int32) -> String? { + // JavaScript returns -1 for null, or the byte length if present + // The actual string is already in tmpRetString side channel + if length < 0 { + return nil + } + return String.bridgeJSLiftReturn(length) + } // MARK: ExportSwift @@ -671,19 +683,24 @@ extension Optional where Wrapped: _BridgedSwiftProtocolWrapper { /// Optional support for Swift heap objects extension Optional where Wrapped: _BridgedSwiftHeapObject { // MARK: ImportTS - @available( - *, - unavailable, - message: "Optional Swift heap objects are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Void {} + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> UnsafeMutableRawPointer { + switch consume self { + case .none: + // Return null pointer for nil + return UnsafeMutableRawPointer(bitPattern: 0).unsafelyUnwrapped + case .some(let value): + // Pass unretained pointer since JS will manage the lifetime + return Unmanaged.passUnretained(value).toOpaque() + } + } - @available( - *, - unavailable, - message: "Optional Swift heap objects are not supported to be returned from imported JS functions" - ) - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ pointer: UnsafeMutableRawPointer) -> Void { + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ pointer: UnsafeMutableRawPointer) -> Wrapped? + { + if pointer == UnsafeMutableRawPointer(bitPattern: 0) { + return nil + } else { + return Wrapped.bridgeJSLiftReturn(pointer) + } } // MARK: ExportSwift diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md index b70b5c02..b6672a0a 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md @@ -23,6 +23,7 @@ import JavaScriptKit @JS protocol Counter { var count: Int { get set } var name: String { get } + var label: String? { get set } func increment(by amount: Int) func reset() func getValue() -> Int @@ -51,6 +52,10 @@ import JavaScriptKit @JS func setCountValue(_ value: Int) { delegate.count = value } + + @JS func updateLabel(_ newLabel: String?) { + delegate.label = newLabel + } } ``` @@ -64,6 +69,7 @@ const { exports } = await init({}); const counterImpl = { count: 0, name: "JSCounter", + label: "Default Label", increment(amount) { this.count += amount; }, @@ -82,6 +88,11 @@ console.log(manager.getCurrentValue()); // 2 console.log(manager.getCounterName()); // "JSCounter" manager.setCountValue(10); console.log(counterImpl.count); // 10 + +manager.updateLabel("Custom Label"); +console.log(counterImpl.label); // "Custom Label" +manager.updateLabel(null); +console.log(counterImpl.label); // null ``` The generated TypeScript interface: @@ -90,6 +101,7 @@ The generated TypeScript interface: export interface Counter { count: number; readonly name: string; + label: string | null; increment(amount: number): void; reset(): void; getValue(): number; @@ -222,32 +234,17 @@ When you pass a JavaScript object implementing a protocol to Swift: | Swift Feature | Status | |:--------------|:-------| -| Method requirements: `func method()` | ✅ | -| Method requirements with parameters | ✅ | -| Method requirements with return values | ✅ | -| Throwing method requirements: `func method() throws(JSException)` | ✅ | -| Async method requirements: `func method() async` | ✅ | -| Property requirements: `var property: Type { get }` | ✅ | -| Property requirements: `var property: Type { get set }` | ✅ | +| Method requirements: `func foo(_ param: String?) -> FooClass?` | ✅ | +| Property requirements: `var property: Type { get }` / `var property: Type { get set }` | ✅ | +| Optional parameters / return values in methods | ✅ | +| Optional properties | ✅ | | Optional protocol methods | ❌ | | Associated types | ❌ | | Protocol inheritance | ❌ | | Protocol composition: `Protocol1 & Protocol2` | ❌ | | Generics | ❌ | -### Type Support for Protocol Properties and Method Parameters - -Protocol properties and method parameters have more limited type support compared to regular exported Swift functions and classes. This is because protocols bridge Swift implementations to JavaScript objects using the TypeScript import mechanism. - -**Supported Types:** -- Primitives: `Bool`, `Int`, `Float`, `Double` -- `String` -- `JSObject` - -**Not Supported:** -- `@JS class` types -- `@JS enum` types (case, raw value, or associated value) -- `@JS protocol` types -- Optional types: `Int?`, `String?`, etc. +**Type Limitations:** +- `@JS enum` types are not supported in protocol signatures (use raw values or separate parameters instead) -> Note: For regular `@JS func` and `@JS class` exports (not within protocols), all these types including optionals, enums, and classes are fully supported. See and for more information. +> Note: Protocol type support matches that of regular `@JS func` and `@JS class` exports. See and for more information. diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 1cdea545..01956551 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -862,6 +862,7 @@ enum APIOptionalResult { @JS protocol Counter { var count: Int { get set } var name: String { get } + var optionalTag: String? { get set } func increment(by amount: Int) func getValue() -> Int func setLabelElements(_ labelPrefix: String, _ labelSuffix: String) @@ -869,6 +870,8 @@ enum APIOptionalResult { func isEven() -> Bool func processGreeter(_ greeter: Greeter) -> String func createGreeter() -> Greeter + func processOptionalGreeter(_ greeter: Greeter?) -> String + func createOptionalGreeter() -> Greeter? } @JS class CounterManager { @@ -918,6 +921,7 @@ enum APIOptionalResult { @JS class SwiftCounter: Counter { @JS var count: Int = 0 @JS let name: String = "SwiftCounter" + @JS var optionalTag: String? = nil private var label: String = "" @JS init() {} @@ -941,14 +945,26 @@ enum APIOptionalResult { @JS func isEven() -> Bool { return count % 2 == 0 } - + @JS func processGreeter(_ greeter: Greeter) -> String { return "SwiftCounter processed: \(greeter.greet())" } - + @JS func createGreeter() -> Greeter { return Greeter(name: "CounterGreeter") } + + @JS func processOptionalGreeter(_ greeter: Greeter?) -> String { + if let greeter = greeter { + return "SwiftCounter processed optional: \(greeter.greet())" + } else { + return "SwiftCounter received nil" + } + } + + @JS func createOptionalGreeter() -> Greeter? { + return Greeter(name: "OptionalCounterGreeter") + } } class ExportAPITests: XCTestCase { diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift index 026c1f32..55cde957 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift @@ -64,6 +64,20 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { return Greeter.bridgeJSLiftReturn(ret) } + func processOptionalGreeter(_ greeter: Optional) -> String { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_processOptionalGreeter") + func _extern_processOptionalGreeter(this: Int32, greeter: UnsafeMutableRawPointer) -> Int32 + let ret = _extern_processOptionalGreeter(this: Int32(bitPattern: jsObject.id), greeter: greeter.bridgeJSLowerParameter()) + return String.bridgeJSLiftReturn(ret) + } + + func createOptionalGreeter() -> Optional { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_createOptionalGreeter") + func _extern_createOptionalGreeter(this: Int32) -> UnsafeMutableRawPointer + let ret = _extern_createOptionalGreeter(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturn(ret) + } + var count: Int { get { @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_count_get") @@ -87,6 +101,20 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { } } + var optionalTag: Optional { + get { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_optionalTag_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_optionalTag_set") + func _extern_set(this: Int32, value: Int32) + _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + } + } + static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyCounter(jsObject: JSObject(id: UInt32(bitPattern: value))) } @@ -3576,6 +3604,28 @@ public func _bjs_SwiftCounter_createGreeter(_self: UnsafeMutableRawPointer) -> U #endif } +@_expose(wasm, "bjs_SwiftCounter_processOptionalGreeter") +@_cdecl("bjs_SwiftCounter_processOptionalGreeter") +public func _bjs_SwiftCounter_processOptionalGreeter(_self: UnsafeMutableRawPointer, greeterIsSome: Int32, greeterValue: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftCounter.bridgeJSLiftParameter(_self).processOptionalGreeter(_: Optional.bridgeJSLiftParameter(greeterIsSome, greeterValue)) + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftCounter_createOptionalGreeter") +@_cdecl("bjs_SwiftCounter_createOptionalGreeter") +public func _bjs_SwiftCounter_createOptionalGreeter(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftCounter.bridgeJSLiftParameter(_self).createOptionalGreeter() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_SwiftCounter_count_get") @_cdecl("bjs_SwiftCounter_count_get") public func _bjs_SwiftCounter_count_get(_self: UnsafeMutableRawPointer) -> Int32 { @@ -3608,6 +3658,27 @@ public func _bjs_SwiftCounter_name_get(_self: UnsafeMutableRawPointer) -> Void { #endif } +@_expose(wasm, "bjs_SwiftCounter_optionalTag_get") +@_cdecl("bjs_SwiftCounter_optionalTag_get") +public func _bjs_SwiftCounter_optionalTag_get(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftCounter.bridgeJSLiftParameter(_self).optionalTag + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftCounter_optionalTag_set") +@_cdecl("bjs_SwiftCounter_optionalTag_set") +public func _bjs_SwiftCounter_optionalTag_set(_self: UnsafeMutableRawPointer, valueIsSome: Int32, valueBytes: Int32, valueLength: Int32) -> Void { + #if arch(wasm32) + SwiftCounter.bridgeJSLiftParameter(_self).optionalTag = Optional.bridgeJSLiftParameter(valueIsSome, valueBytes, valueLength) + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_SwiftCounter_deinit") @_cdecl("bjs_SwiftCounter_deinit") public func _bjs_SwiftCounter_deinit(pointer: UnsafeMutableRawPointer) { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json index 79b0884b..f97beee6 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json @@ -1543,6 +1543,56 @@ "_0" : "Greeter" } } + }, + { + "abiName" : "bjs_SwiftCounter_processOptionalGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalGreeter", + "parameters" : [ + { + "label" : "_", + "name" : "greeter", + "type" : { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_SwiftCounter_createOptionalGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "createOptionalGreeter", + "parameters" : [ + + ], + "returnType" : { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + } } ], "name" : "SwiftCounter", @@ -1566,6 +1616,20 @@ } } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "optionalTag", + "type" : { + "optional" : { + "_0" : { + "string" : { + + } + } + } + } } ], "swiftCallName" : "SwiftCounter" @@ -5997,6 +6061,56 @@ "_0" : "Greeter" } } + }, + { + "abiName" : "bjs_Counter_processOptionalGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "processOptionalGreeter", + "parameters" : [ + { + "label" : "_", + "name" : "greeter", + "type" : { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + } + } + ], + "returnType" : { + "string" : { + + } + } + }, + { + "abiName" : "bjs_Counter_createOptionalGreeter", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "createOptionalGreeter", + "parameters" : [ + + ], + "returnType" : { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + } } ], "name" : "Counter", @@ -6018,6 +6132,19 @@ } } + }, + { + "isReadonly" : false, + "name" : "optionalTag", + "type" : { + "optional" : { + "_0" : { + "string" : { + + } + } + } + } } ] } diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index f5bbc355..73bc7279 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -814,13 +814,18 @@ function testProtocolSupport(exports) { const jsCounter = { count: 0, name: "JSCounter", + optionalTag: null, increment(amount) { counterValue += amount; this.count += amount; }, getValue() { return counterValue; }, setLabelElements(labelPrefix, labelSuffix) { counterLabel = labelPrefix + labelSuffix; }, getLabel() { return counterLabel; }, isEven() { return counterValue % 2 === 0; }, processGreeter(greeter) { return `JSCounter processed: ${greeter.greet()}`; }, - createGreeter() { return new exports.Greeter("JSCounterGreeter"); } + createGreeter() { return new exports.Greeter("JSCounterGreeter"); }, + processOptionalGreeter(greeter) { + return greeter ? `JSCounter processed optional: ${greeter.greet()}` : "JSCounter received null"; + }, + createOptionalGreeter() { return new exports.Greeter("JSOptionalGreeter"); } }; const manager = new exports.CounterManager(jsCounter); @@ -884,6 +889,29 @@ function testProtocolSupport(exports) { assert.equal(swiftCreatedGreeter.greet(), "Hello, CounterGreeter!"); swiftCreatedGreeter.release(); + const optGreeterTest = new exports.Greeter("OptionalTest"); + assert.equal(jsCounter.processOptionalGreeter(optGreeterTest), "JSCounter processed optional: Hello, OptionalTest!"); + assert.equal(jsCounter.processOptionalGreeter(null), "JSCounter received null"); + assert.equal(swiftCounter.processOptionalGreeter(optGreeterTest), "SwiftCounter processed optional: Hello, OptionalTest!"); + assert.equal(swiftCounter.processOptionalGreeter(null), "SwiftCounter received nil"); + optGreeterTest.release(); + + const jsOptGreeter = jsCounter.createOptionalGreeter(); + assert.notEqual(jsOptGreeter, null); + assert.equal(jsOptGreeter.name, "JSOptionalGreeter"); + jsOptGreeter.release(); + + const swiftOptGreeter = swiftCounter.createOptionalGreeter(); + assert.notEqual(swiftOptGreeter, null); + assert.equal(swiftOptGreeter.name, "OptionalCounterGreeter"); + swiftOptGreeter.release(); + + assert.equal(jsCounter.optionalTag, null); + jsCounter.optionalTag = "test-tag"; + assert.equal(jsCounter.optionalTag, "test-tag"); + jsCounter.optionalTag = null; + assert.equal(jsCounter.optionalTag, null); + testGreeter.release(); swiftManager.release(); @@ -894,13 +922,18 @@ function testProtocolSupport(exports) { const optionalCounter = { count: 100, name: "OptionalCounter", + optionalTag: "optional-tag", increment(amount) { optionalCounterValue += amount; this.count += amount; }, getValue() { return optionalCounterValue; }, setLabelElements(labelPrefix, labelSuffix) { optionalCounterLabel = labelPrefix + labelSuffix; }, getLabel() { return optionalCounterLabel; }, isEven() { return optionalCounterValue % 2 === 0; }, processGreeter(greeter) { return `OptionalCounter processed: ${greeter.greet()}`; }, - createGreeter() { return new exports.Greeter("OptionalCounterGreeter"); } + createGreeter() { return new exports.Greeter("OptionalCounterGreeter"); }, + processOptionalGreeter(greeter) { + return greeter ? `OptionalCounter processed optional: ${greeter.greet()}` : "OptionalCounter received null"; + }, + createOptionalGreeter() { return null; } }; let mainCounterValue = 0; @@ -908,13 +941,18 @@ function testProtocolSupport(exports) { const mainCounter = { count: 0, name: "MainCounter", + optionalTag: null, increment(amount) { mainCounterValue += amount; this.count += amount; }, getValue() { return mainCounterValue; }, setLabelElements(labelPrefix, labelSuffix) { mainCounterLabel = labelPrefix + labelSuffix; }, getLabel() { return mainCounterLabel; }, isEven() { return mainCounterValue % 2 === 0; }, processGreeter(greeter) { return `MainCounter processed: ${greeter.greet()}`; }, - createGreeter() { return new exports.Greeter("MainCounterGreeter"); } + createGreeter() { return new exports.Greeter("MainCounterGreeter"); }, + processOptionalGreeter(greeter) { + return greeter ? `MainCounter processed optional: ${greeter.greet()}` : "MainCounter received null"; + }, + createOptionalGreeter() { return new exports.Greeter("MainOptionalGreeter"); } }; const managerWithOptional = new exports.CounterManager(mainCounter); From 128f696dc6e275d76c20afcd55dd8a790c54d458 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Wed, 15 Oct 2025 15:54:07 +0200 Subject: [PATCH 4/6] BridgeJS: Protocol support for enum values (all types + optionals) BridgeJS: Final refinings to enum support and revisiting tests --- .../Sources/BridgeJSCore/ExportSwift.swift | 153 +++-- .../Sources/BridgeJSCore/ImportTS.swift | 71 +- .../Sources/BridgeJSLink/JSGlueGen.swift | 75 +- .../BridgeJSToolTests/Inputs/Protocol.swift | 15 + .../BridgeJSLinkTests/Protocol.Export.d.ts | 27 + .../BridgeJSLinkTests/Protocol.Export.js | 122 ++++ .../EnumAssociatedValue.swift | 254 ++++++- .../ExportSwiftTests/Protocol.json | 147 ++++ .../ExportSwiftTests/Protocol.swift | 107 +++ .../ExportSwiftTests/StaticFunctions.swift | 31 +- .../JavaScriptKit/BridgeJSInstrincics.swift | 212 +++--- .../BridgeJSRuntimeTests/ExportAPITests.swift | 64 +- .../Generated/BridgeJS.ExportSwift.swift | 643 +++++++++++++----- .../JavaScript/BridgeJS.ExportSwift.json | 197 ++++-- Tests/prelude.mjs | 223 +++--- 15 files changed, 1830 insertions(+), 511 deletions(-) diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 526b2562..7aa4503f 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -1751,13 +1751,13 @@ public class ExportSwift { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> \(raw: typeName) { - return \(raw: typeName)(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> \(raw: typeName) { return \(raw: typeName)(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -1774,13 +1774,32 @@ public class ExportSwift { func renderAssociatedValueEnumHelpers(_ enumDef: ExportedEnum) -> DeclSyntax { let typeName = enumDef.swiftCallName return """ - extension \(raw: typeName): _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> \(raw: typeName) { + extension \(raw: typeName): _BridgedSwiftAssociatedValueEnum { + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> \(raw: typeName) { switch caseId { \(raw: generateStackLiftSwitchCases(enumDef: enumDef).joined(separator: "\n")) default: fatalError("Unknown \(raw: typeName) case ID: \\(caseId)") } } + + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + \(raw: generateLowerParameterSwitchCases(enumDef: enumDef).joined(separator: "\n")) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> \(raw: typeName) { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> \(raw: typeName) { + return _bridgeJSLiftFromCaseId(caseId) + } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { @@ -1849,6 +1868,80 @@ public class ExportSwift { return cases } + /// Generates code to push associated value payloads to side channels + /// This helper is reused by both lowerParameter and lowerReturn to avoid duplication + private func generatePayloadPushingCode( + associatedValues: [AssociatedValue] + ) -> [String] { + var bodyLines: [String] = [] + for (index, associatedValue) in associatedValues.enumerated() { + let paramName = associatedValue.label ?? "param\(index)" + switch associatedValue.type { + case .string: + bodyLines.append("var __bjs_\(paramName) = \(paramName)") + bodyLines.append("__bjs_\(paramName).withUTF8 { ptr in") + bodyLines.append("_swift_js_push_string(ptr.baseAddress, Int32(ptr.count))") + bodyLines.append("}") + case .int: + bodyLines.append("_swift_js_push_int(Int32(\(paramName)))") + case .bool: + bodyLines.append("_swift_js_push_int(\(paramName) ? 1 : 0)") + case .float: + bodyLines.append("_swift_js_push_f32(\(paramName))") + case .double: + bodyLines.append("_swift_js_push_f64(\(paramName))") + case .optional(let wrappedType): + bodyLines.append("let __bjs_isSome_\(paramName) = \(paramName) != nil") + bodyLines.append("if let __bjs_unwrapped_\(paramName) = \(paramName) {") + switch wrappedType { + case .string: + bodyLines.append("var __bjs_str_\(paramName) = __bjs_unwrapped_\(paramName)") + bodyLines.append("__bjs_str_\(paramName).withUTF8 { ptr in") + bodyLines.append("_swift_js_push_string(ptr.baseAddress, Int32(ptr.count))") + bodyLines.append("}") + case .int: + bodyLines.append("_swift_js_push_int(Int32(__bjs_unwrapped_\(paramName)))") + case .bool: + bodyLines.append("_swift_js_push_int(__bjs_unwrapped_\(paramName) ? 1 : 0)") + case .float: + bodyLines.append("_swift_js_push_f32(__bjs_unwrapped_\(paramName))") + case .double: + bodyLines.append("_swift_js_push_f64(__bjs_unwrapped_\(paramName))") + default: + bodyLines.append( + "preconditionFailure(\"BridgeJS: unsupported optional wrapped type in generated code\")" + ) + } + bodyLines.append("}") + bodyLines.append("_swift_js_push_int(__bjs_isSome_\(paramName) ? 1 : 0)") + default: + bodyLines.append( + "preconditionFailure(\"BridgeJS: unsupported associated value type in generated code\")" + ) + } + } + return bodyLines + } + + private func generateLowerParameterSwitchCases(enumDef: ExportedEnum) -> [String] { + var cases: [String] = [] + for (caseIndex, enumCase) in enumDef.cases.enumerated() { + if enumCase.associatedValues.isEmpty { + cases.append("case .\(enumCase.name):") + cases.append("return Int32(\(caseIndex))") + } else { + let payloadCode = generatePayloadPushingCode(associatedValues: enumCase.associatedValues) + let pattern = enumCase.associatedValues.enumerated() + .map { index, associatedValue in "let \(associatedValue.label ?? "param\(index)")" } + .joined(separator: ", ") + cases.append("case .\(enumCase.name)(\(pattern)):") + cases.append(contentsOf: payloadCode) + cases.append("return Int32(\(caseIndex))") + } + } + return cases + } + private func generateReturnSwitchCases(enumDef: ExportedEnum) -> [String] { var cases: [String] = [] for (caseIndex, enumCase) in enumDef.cases.enumerated() { @@ -1856,59 +1949,13 @@ public class ExportSwift { cases.append("case .\(enumCase.name):") cases.append("_swift_js_push_tag(Int32(\(caseIndex)))") } else { - var bodyLines: [String] = [] - bodyLines.append("_swift_js_push_tag(Int32(\(caseIndex)))") - for (index, associatedValue) in enumCase.associatedValues.enumerated() { - let paramName = associatedValue.label ?? "param\(index)" - switch associatedValue.type { - case .string: - bodyLines.append("var __bjs_\(paramName) = \(paramName)") - bodyLines.append("__bjs_\(paramName).withUTF8 { ptr in") - bodyLines.append("_swift_js_push_string(ptr.baseAddress, Int32(ptr.count))") - bodyLines.append("}") - case .int: - bodyLines.append("_swift_js_push_int(Int32(\(paramName)))") - case .bool: - bodyLines.append("_swift_js_push_int(\(paramName) ? 1 : 0)") - case .float: - bodyLines.append("_swift_js_push_f32(\(paramName))") - case .double: - bodyLines.append("_swift_js_push_f64(\(paramName))") - case .optional(let wrappedType): - bodyLines.append("let __bjs_isSome_\(paramName) = \(paramName) != nil") - bodyLines.append("if let __bjs_unwrapped_\(paramName) = \(paramName) {") - switch wrappedType { - case .string: - bodyLines.append("var __bjs_str_\(paramName) = __bjs_unwrapped_\(paramName)") - bodyLines.append("__bjs_str_\(paramName).withUTF8 { ptr in") - bodyLines.append("_swift_js_push_string(ptr.baseAddress, Int32(ptr.count))") - bodyLines.append("}") - case .int: - bodyLines.append("_swift_js_push_int(Int32(__bjs_unwrapped_\(paramName)))") - case .bool: - bodyLines.append("_swift_js_push_int(__bjs_unwrapped_\(paramName) ? 1 : 0)") - case .float: - bodyLines.append("_swift_js_push_f32(__bjs_unwrapped_\(paramName))") - case .double: - bodyLines.append("_swift_js_push_f64(__bjs_unwrapped_\(paramName))") - default: - bodyLines.append( - "preconditionFailure(\"BridgeJS: unsupported optional wrapped type in generated code\")" - ) - } - bodyLines.append("}") - bodyLines.append("_swift_js_push_int(__bjs_isSome_\(paramName) ? 1 : 0)") - default: - bodyLines.append( - "preconditionFailure(\"BridgeJS: unsupported associated value type in generated code\")" - ) - } - } let pattern = enumCase.associatedValues.enumerated() .map { index, associatedValue in "let \(associatedValue.label ?? "param\(index)")" } .joined(separator: ", ") cases.append("case .\(enumCase.name)(\(pattern)):") - cases.append(contentsOf: bodyLines) + cases.append("_swift_js_push_tag(Int32(\(caseIndex)))") + let payloadCode = generatePayloadPushingCode(associatedValues: enumCase.associatedValues) + cases.append(contentsOf: payloadCode) } } return cases diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 52ff813a..26e22e87 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -447,14 +447,41 @@ extension BridgeType { } case .swiftProtocol: throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") - case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum: - throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") + case .caseEnum: + switch context { + case .importTS: + throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") + case .protocolExport: + return LoweringParameterInfo(loweredParameters: [("value", .i32)]) + } + case .rawValueEnum(_, let rawType): + switch context { + case .importTS: + throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") + case .protocolExport: + let wasmType = rawType == .string ? WasmCoreType.i32 : (rawType.wasmCoreType ?? .i32) + return LoweringParameterInfo(loweredParameters: [("value", wasmType)]) + } + case .associatedValueEnum: + switch context { + case .importTS: + throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") + case .protocolExport: + return LoweringParameterInfo(loweredParameters: [("caseId", .i32)]) + } + case .namespaceEnum: + throw BridgeJSCoreError("Namespace enums cannot be used as parameters") case .optional(let wrappedType): switch context { case .importTS: throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") case .protocolExport: - return try wrappedType.loweringParameterInfo(context: context) + let wrappedInfo = try wrappedType.loweringParameterInfo(context: context) + guard wrappedInfo.loweredParameters.count == 1 else { + throw BridgeJSCoreError("Optional wrapped type must lower to single parameter") + } + let (_, wrappedWasmType) = wrappedInfo.loweredParameters[0] + return LoweringParameterInfo(loweredParameters: [("value", wrappedWasmType)]) } } } @@ -494,22 +521,38 @@ extension BridgeType { } case .swiftProtocol: throw BridgeJSCoreError("swiftProtocol is not supported in imported signatures") - case .caseEnum, .rawValueEnum, .associatedValueEnum, .namespaceEnum: - throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") - case .optional: + case .caseEnum: switch context { case .importTS: - throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") + throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") + case .protocolExport: + return LiftingReturnInfo(valueToLift: .i32) + } + case .rawValueEnum(_, let rawType): + switch context { + case .importTS: + throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") + case .protocolExport: + let wasmType = rawType == .string ? WasmCoreType.i32 : (rawType.wasmCoreType ?? .i32) + return LiftingReturnInfo(valueToLift: wasmType) + } + case .associatedValueEnum: + switch context { + case .importTS: + throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") case .protocolExport: - // For Optional, return the length (or -1 for null) - if case .optional(.string) = self { - return .string - } - if case .optional(.swiftHeapObject) = self { - return LiftingReturnInfo(valueToLift: .pointer) - } return LiftingReturnInfo(valueToLift: nil) } + case .namespaceEnum: + throw BridgeJSCoreError("Namespace enums cannot be used as return values") + case .optional(let wrappedType): + switch context { + case .importTS: + throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") + case .protocolExport: + let wrappedInfo = try wrappedType.liftingReturnInfo(context: context) + return wrappedInfo + } } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 1e92b09a..45397471 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -490,9 +490,9 @@ struct IntrinsicJSFragment: Sendable { static func optionalLowerReturn(wrappedType: BridgeType) throws -> IntrinsicJSFragment { switch wrappedType { case .bool, .int, .float, .double, .string, .swiftHeapObject, .jsObject, .swiftProtocol, .caseEnum, - .rawValueEnum: + .rawValueEnum, .associatedValueEnum: break - case .void, .optional, .associatedValueEnum, .namespaceEnum: + case .void, .optional, .namespaceEnum: throw BridgeJSLinkError(message: "Unsupported optional wrapped type for protocol export: \(wrappedType)") } @@ -586,6 +586,23 @@ struct IntrinsicJSFragment: Sendable { "bjs[\"swift_js_return_optional_int\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) | 0) : 0);" ) } + case .associatedValueEnum(let fullName): + let base = fullName.components(separatedBy: ".").last ?? fullName + let caseIdVar = scope.variable("caseId") + let cleanupVar = scope.variable("cleanup") + printer.write("if (\(isSomeVar)) {") + printer.indent { + printer.write( + "const { caseId: \(caseIdVar), cleanup: \(cleanupVar) } = enumHelpers.\(base).lower(\(value));" + ) + cleanupCode.write("if (\(cleanupVar)) { \(cleanupVar)(); }") + printer.write("bjs[\"swift_js_return_optional_int\"](1, \(caseIdVar));") + } + printer.write("} else {") + printer.indent { + printer.write("bjs[\"swift_js_return_optional_int\"](0, 0);") + } + printer.write("}") default: () } @@ -693,11 +710,27 @@ struct IntrinsicJSFragment: Sendable { case .bool: return .boolLiftParameter default: return .identity } - case .associatedValueEnum(let string): - throw BridgeJSLinkError( - message: - "Associated value enums are not supported to be passed as parameters to imported JS functions: \(string)" - ) + case .associatedValueEnum(let fullName): + switch context { + case .importTS: + throw BridgeJSLinkError( + message: + "Associated value enums are not supported to be passed as parameters to imported JS functions: \(fullName)" + ) + case .protocolExport: + let base = fullName.components(separatedBy: ".").last ?? fullName + return IntrinsicJSFragment( + parameters: ["caseId"], + printCode: { arguments, scope, printer, cleanupCode in + let caseId = arguments[0] + let resultVar = scope.variable("enumValue") + printer.write( + "const \(resultVar) = enumHelpers.\(base).raise(\(caseId), \(JSGlueVariableScope.reservedTmpRetStrings), \(JSGlueVariableScope.reservedTmpRetInts), \(JSGlueVariableScope.reservedTmpRetF32s), \(JSGlueVariableScope.reservedTmpRetF64s));" + ) + return [resultVar] + } + ) + } case .namespaceEnum(let string): throw BridgeJSLinkError( message: @@ -743,10 +776,30 @@ struct IntrinsicJSFragment: Sendable { case .bool: return .boolLowerReturn default: return .identity } - case .associatedValueEnum(let string): - throw BridgeJSLinkError( - message: "Associated value enums are not supported to be returned from imported JS functions: \(string)" - ) + case .associatedValueEnum(let fullName): + switch context { + case .importTS: + throw BridgeJSLinkError( + message: + "Associated value enums are not supported to be returned from imported JS functions: \(fullName)" + ) + case .protocolExport: + let base = fullName.components(separatedBy: ".").last ?? fullName + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, scope, printer, cleanupCode in + let value = arguments[0] + let caseIdVar = scope.variable("caseId") + let cleanupVar = scope.variable("cleanup") + printer.write( + "const { caseId: \(caseIdVar), cleanup: \(cleanupVar) } = enumHelpers.\(base).lower(\(value));" + ) + cleanupCode.write("if (\(cleanupVar)) { \(cleanupVar)(); }") + printer.write("return \(caseIdVar);") + return [] + } + ) + } case .namespaceEnum(let string): throw BridgeJSLinkError( message: "Namespace enums are not supported to be returned from imported JS functions: \(string)" diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift index 63a6d9ac..9f2556e9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift @@ -1,5 +1,15 @@ import JavaScriptKit +@JS enum ExampleEnum: String { + case test = "test" + case test2 = "test2" +} + +@JS enum Result { + case success(String) + case failure(Int) +} + @JS class Helper { @JS var value: Int @@ -16,6 +26,8 @@ import JavaScriptKit var eventCount: Int { get set } var delegateName: String { get } var optionalName: String? { get set } + var myEnum: ExampleEnum { get set } + var result: Result? { get set } func onSomethingHappened() func onValueChanged(_ value: String) func onCountUpdated(count: Int) -> Bool @@ -25,6 +37,9 @@ import JavaScriptKit func createHelper() -> Helper func onOptionalHelperUpdated(_ helper: Helper?) func createOptionalHelper() -> Helper? + func createEnum() -> ExampleEnum + func handleResult(_ result: Result) + func getResult() -> Result } @JS class MyViewController { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts index 2d489979..9e64ddff 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts @@ -14,11 +14,36 @@ export interface MyViewControllerDelegate { createHelper(): Helper; onOptionalHelperUpdated(helper: Helper | null): void; createOptionalHelper(): Helper | null; + createEnum(): ExampleEnumTag; + handleResult(result: ResultTag): void; + getResult(): ResultTag; eventCount: number; readonly delegateName: string; optionalName: string | null; + myEnum: ExampleEnumTag; + result: ResultTag | null; } +export const ExampleEnumValues: { + readonly Test: "test"; + readonly Test2: "test2"; +}; +export type ExampleEnumTag = typeof ExampleEnumValues[keyof typeof ExampleEnumValues]; + +export const ResultValues: { + readonly Tag: { + readonly Success: 0; + readonly Failure: 1; + }; +}; + +export type ResultTag = + { tag: typeof ResultValues.Tag.Success; param0: string } | { tag: typeof ResultValues.Tag.Failure; param0: number } + +export type ExampleEnumObject = typeof ExampleEnumValues; + +export type ResultObject = typeof ResultValues; + /// Represents a Swift heap object like a class instance or an actor instance. export interface SwiftHeapObject { /// Release the heap object. @@ -47,6 +72,8 @@ export type Exports = { MyViewController: { new(delegate: MyViewControllerDelegate): MyViewController; } + ExampleEnum: ExampleEnumObject + Result: ResultObject } export type Imports = { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js index 1d9329c3..8aa18d39 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js @@ -4,6 +4,57 @@ // To update this file, just rebuild your project or run // `swift package bridge-js`. +export const ExampleEnumValues = { + Test: "test", + Test2: "test2", +}; + +export const ResultValues = { + Tag: { + Success: 0, + Failure: 1, + }, +}; + +const __bjs_createResultValuesHelpers = () => { + return (tmpParamInts, tmpParamF32s, tmpParamF64s, textEncoder, swift) => ({ + lower: (value) => { + const enumTag = value.tag; + switch (enumTag) { + case ResultValues.Tag.Success: { + const bytes = textEncoder.encode(value.param0); + const id = swift.memory.retain(bytes); + tmpParamInts.push(bytes.length); + tmpParamInts.push(id); + const cleanup = () => { + swift.memory.release(id); + }; + return { caseId: ResultValues.Tag.Success, cleanup }; + } + case ResultValues.Tag.Failure: { + tmpParamInts.push((value.param0 | 0)); + const cleanup = undefined; + return { caseId: ResultValues.Tag.Failure, cleanup }; + } + default: throw new Error("Unknown ResultValues tag: " + String(enumTag)); + } + }, + raise: (tmpRetTag, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s) => { + const tag = tmpRetTag | 0; + switch (tag) { + case ResultValues.Tag.Success: { + const string = tmpRetStrings.pop(); + return { tag: ResultValues.Tag.Success, param0: string }; + } + case ResultValues.Tag.Failure: { + const int = tmpRetInts.pop(); + return { tag: ResultValues.Tag.Failure, param0: int }; + } + default: throw new Error("Unknown ResultValues tag returned from Swift: " + String(tag)); + } + } + }); +}; export async function createInstantiator(options, swift) { let instance; let memory; @@ -26,6 +77,7 @@ export async function createInstantiator(options, swift) { let tmpParamInts = []; let tmpParamF32s = []; let tmpParamF64s = []; + const enumHelpers = {}; return { /** @@ -204,6 +256,45 @@ export async function createInstantiator(options, swift) { setException(error); } } + TestModule["bjs_MyViewControllerDelegate_myEnum_get"] = function bjs_MyViewControllerDelegate_myEnum_get(self) { + try { + let ret = swift.memory.getObject(self).myEnum; + tmpRetBytes = textEncoder.encode(ret); + return tmpRetBytes.length; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_myEnum_set"] = function bjs_MyViewControllerDelegate_myEnum_set(self, value) { + try { + const valueObject = swift.memory.getObject(value); + swift.memory.release(value); + swift.memory.getObject(self).myEnum = valueObject; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_result_get"] = function bjs_MyViewControllerDelegate_result_get(self) { + try { + let ret = swift.memory.getObject(self).result; + const isSome = ret != null; + if (isSome) { + const { caseId: caseId, cleanup: cleanup } = enumHelpers.Result.lower(ret); + bjs["swift_js_return_optional_int"](1, caseId); + } else { + bjs["swift_js_return_optional_int"](0, 0); + } + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_result_set"] = function bjs_MyViewControllerDelegate_result_set(self, valueIsSome, valueWrappedValue) { + try { + swift.memory.getObject(self).result = valueIsSome ? valueWrappedValue : null; + } catch (error) { + setException(error); + } + } TestModule["bjs_MyViewControllerDelegate_onSomethingHappened"] = function bjs_MyViewControllerDelegate_onSomethingHappened(self) { try { swift.memory.getObject(self).onSomethingHappened(); @@ -281,11 +372,40 @@ export async function createInstantiator(options, swift) { setException(error); } } + TestModule["bjs_MyViewControllerDelegate_createEnum"] = function bjs_MyViewControllerDelegate_createEnum(self) { + try { + let ret = swift.memory.getObject(self).createEnum(); + tmpRetBytes = textEncoder.encode(ret); + return tmpRetBytes.length; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_handleResult"] = function bjs_MyViewControllerDelegate_handleResult(self, result) { + try { + const enumValue = enumHelpers.Result.raise(result, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s); + swift.memory.getObject(self).handleResult(enumValue); + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_getResult"] = function bjs_MyViewControllerDelegate_getResult(self) { + try { + let ret = swift.memory.getObject(self).getResult(); + const { caseId: caseId, cleanup: cleanup } = enumHelpers.Result.lower(ret); + return caseId; + } catch (error) { + setException(error); + } + } }, setInstance: (i) => { instance = i; memory = instance.exports.memory; + const ResultHelpers = __bjs_createResultValuesHelpers()(tmpParamInts, tmpParamF32s, tmpParamF64s, textEncoder, swift); + enumHelpers.Result = ResultHelpers; + setException = (error) => { instance.exports._swift_js_exception.value = swift.memory.retain(error) } @@ -393,6 +513,8 @@ export async function createInstantiator(options, swift) { return { Helper, MyViewController, + ExampleEnum: ExampleEnumValues, + Result: ResultValues, }; }, } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift index 008eeda0..ce952ca9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift @@ -7,7 +7,9 @@ @_spi(BridgeJS) import JavaScriptKit extension APIResult: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIResult { + // MARK: Private Helper + + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> APIResult { switch caseId { case 0: return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -26,6 +28,44 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .failure(let param0): + _swift_js_push_int(Int32(param0)) + return Int32(1) + case .flag(let param0): + _swift_js_push_int(param0 ? 1 : 0) + return Int32(2) + case .rate(let param0): + _swift_js_push_f32(param0) + return Int32(3) + case .precise(let param0): + _swift_js_push_f64(param0) + return Int32(4) + case .info: + return Int32(5) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> APIResult { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIResult { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): @@ -53,7 +93,9 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } extension ComplexResult: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> ComplexResult { + // MARK: Private Helper + + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> ComplexResult { switch caseId { case 0: return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -72,6 +114,72 @@ extension ComplexResult: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .error(let param0, let param1): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + _swift_js_push_int(Int32(param1)) + return Int32(1) + case .status(let param0, let param1, let param2): + _swift_js_push_int(param0 ? 1 : 0) + _swift_js_push_int(Int32(param1)) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(2) + case .coordinates(let param0, let param1, let param2): + _swift_js_push_f64(param0) + _swift_js_push_f64(param1) + _swift_js_push_f64(param2) + return Int32(3) + case .comprehensive(let param0, let param1, let param2, let param3, let param4, let param5, let param6, let param7, let param8): + _swift_js_push_int(param0 ? 1 : 0) + _swift_js_push_int(param1 ? 1 : 0) + _swift_js_push_int(Int32(param2)) + _swift_js_push_int(Int32(param3)) + _swift_js_push_f64(param4) + _swift_js_push_f64(param5) + var __bjs_param6 = param6 + __bjs_param6.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + var __bjs_param7 = param7 + __bjs_param7.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + var __bjs_param8 = param8 + __bjs_param8.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(4) + case .info: + return Int32(5) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> ComplexResult { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> ComplexResult { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): @@ -127,7 +235,9 @@ extension ComplexResult: _BridgedSwiftAssociatedValueEnum { } extension Utilities.Result: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> Utilities.Result { + // MARK: Private Helper + + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> Utilities.Result { switch caseId { case 0: return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -140,6 +250,45 @@ extension Utilities.Result: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .failure(let param0, let param1): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + _swift_js_push_int(Int32(param1)) + return Int32(1) + case .status(let param0, let param1, let param2): + _swift_js_push_int(param0 ? 1 : 0) + _swift_js_push_int(Int32(param1)) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(2) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> Utilities.Result { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> Utilities.Result { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): @@ -168,7 +317,9 @@ extension Utilities.Result: _BridgedSwiftAssociatedValueEnum { } extension NetworkingResult: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> NetworkingResult { + // MARK: Private Helper + + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> NetworkingResult { switch caseId { case 0: return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -179,6 +330,37 @@ extension NetworkingResult: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .failure(let param0, let param1): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + _swift_js_push_int(Int32(param1)) + return Int32(1) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> NetworkingResult { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> NetworkingResult { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): @@ -199,7 +381,9 @@ extension NetworkingResult: _BridgedSwiftAssociatedValueEnum { } extension APIOptionalResult: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIOptionalResult { + // MARK: Private Helper + + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> APIOptionalResult { switch caseId { case 0: return .success(Optional.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -212,6 +396,66 @@ extension APIOptionalResult: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + let __bjs_isSome_param0 = param0 != nil + if let __bjs_unwrapped_param0 = param0 { + var __bjs_str_param0 = __bjs_unwrapped_param0 + __bjs_str_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + } + _swift_js_push_int(__bjs_isSome_param0 ? 1 : 0) + return Int32(0) + case .failure(let param0, let param1): + let __bjs_isSome_param0 = param0 != nil + if let __bjs_unwrapped_param0 = param0 { + _swift_js_push_int(Int32(__bjs_unwrapped_param0)) + } + _swift_js_push_int(__bjs_isSome_param0 ? 1 : 0) + let __bjs_isSome_param1 = param1 != nil + if let __bjs_unwrapped_param1 = param1 { + _swift_js_push_int(__bjs_unwrapped_param1 ? 1 : 0) + } + _swift_js_push_int(__bjs_isSome_param1 ? 1 : 0) + return Int32(1) + case .status(let param0, let param1, let param2): + let __bjs_isSome_param0 = param0 != nil + if let __bjs_unwrapped_param0 = param0 { + _swift_js_push_int(__bjs_unwrapped_param0 ? 1 : 0) + } + _swift_js_push_int(__bjs_isSome_param0 ? 1 : 0) + let __bjs_isSome_param1 = param1 != nil + if let __bjs_unwrapped_param1 = param1 { + _swift_js_push_int(Int32(__bjs_unwrapped_param1)) + } + _swift_js_push_int(__bjs_isSome_param1 ? 1 : 0) + let __bjs_isSome_param2 = param2 != nil + if let __bjs_unwrapped_param2 = param2 { + var __bjs_str_param2 = __bjs_unwrapped_param2 + __bjs_str_param2.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + } + _swift_js_push_int(__bjs_isSome_param2 ? 1 : 0) + return Int32(2) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> APIOptionalResult { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIOptionalResult { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json index 30abfc91..bddcf2aa 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json @@ -250,7 +250,71 @@ } ], "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "test", + "rawValue" : "test" + }, + { + "associatedValues" : [ + + ], + "name" : "test2", + "rawValue" : "test2" + } + ], + "emitStyle" : "const", + "name" : "ExampleEnum", + "rawType" : "String", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "ExampleEnum" + }, + { + "cases" : [ + { + "associatedValues" : [ + { + "type" : { + "string" : { + + } + } + } + ], + "name" : "success" + }, + { + "associatedValues" : [ + { + "type" : { + "int" : { + + } + } + } + ], + "name" : "failure" + } + ], + "emitStyle" : "const", + "name" : "Result", + "staticMethods" : [ + + ], + "staticProperties" : [ + ], + "swiftCallName" : "Result" + } ], "functions" : [ @@ -468,6 +532,66 @@ } } } + }, + { + "abiName" : "bjs_MyViewControllerDelegate_createEnum", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "createEnum", + "parameters" : [ + + ], + "returnType" : { + "rawValueEnum" : { + "_0" : "ExampleEnum", + "_1" : "String" + } + } + }, + { + "abiName" : "bjs_MyViewControllerDelegate_handleResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "handleResult", + "parameters" : [ + { + "label" : "_", + "name" : "result", + "type" : { + "associatedValueEnum" : { + "_0" : "Result" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_MyViewControllerDelegate_getResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getResult", + "parameters" : [ + + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "Result" + } + } } ], "name" : "MyViewControllerDelegate", @@ -502,6 +626,29 @@ } } } + }, + { + "isReadonly" : false, + "name" : "myEnum", + "type" : { + "rawValueEnum" : { + "_0" : "ExampleEnum", + "_1" : "String" + } + } + }, + { + "isReadonly" : false, + "name" : "result", + "type" : { + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "Result" + } + } + } + } } ] } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift index ea1d71ea..8bd37e8e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift @@ -67,6 +67,26 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto return Optional.bridgeJSLiftReturn(ret) } + func createEnum() -> ExampleEnum { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_createEnum") + func _extern_createEnum(this: Int32) -> Int32 + let ret = _extern_createEnum(this: Int32(bitPattern: jsObject.id)) + return ExampleEnum.bridgeJSLiftReturn(ret) + } + + func handleResult(_ result: Result) { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_handleResult") + func _extern_handleResult(this: Int32, result: Int32) + _extern_handleResult(this: Int32(bitPattern: jsObject.id), result: result.bridgeJSLowerParameter()) + } + + func getResult() -> Result { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_getResult") + func _extern_getResult(this: Int32) + _extern_getResult(this: Int32(bitPattern: jsObject.id)) + return Result.bridgeJSLiftReturn() + } + var eventCount: Int { get { @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_eventCount_get") @@ -104,11 +124,98 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto } } + var myEnum: ExampleEnum { + get { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_myEnum_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return ExampleEnum.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_myEnum_set") + func _extern_set(this: Int32, value: Int32) + _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + } + } + + var result: Optional { + get { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_result_get") + func _extern_get(this: Int32) + _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturn() + } + set { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_result_set") + func _extern_set(this: Int32, value: Int32) + _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + } + } + static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyMyViewControllerDelegate(jsObject: JSObject(id: UInt32(bitPattern: value))) } } +extension ExampleEnum: _BridgedSwiftEnumNoPayload { +} + +extension Result: _BridgedSwiftAssociatedValueEnum { + // MARK: Private Helper + + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> Result { + switch caseId { + case 0: + return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) + case 1: + return .failure(Int.bridgeJSLiftParameter(_swift_js_pop_param_int32())) + default: + fatalError("Unknown Result case ID: \(caseId)") + } + } + + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .failure(let param0): + _swift_js_push_int(Int32(param0)) + return Int32(1) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> Result { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> Result { + return _bridgeJSLiftFromCaseId(caseId) + } + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { + switch self { + case .success(let param0): + _swift_js_push_tag(Int32(0)) + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + case .failure(let param0): + _swift_js_push_tag(Int32(1)) + _swift_js_push_int(Int32(param0)) + } + } +} + @_expose(wasm, "bjs_Helper_init") @_cdecl("bjs_Helper_init") public func _bjs_Helper_init(value: Int32) -> UnsafeMutableRawPointer { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticFunctions.swift index 4e301151..a26d5ea1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticFunctions.swift @@ -53,7 +53,9 @@ public func _bjs_Calculator_static_square(value: Int32) -> Int32 { } extension APIResult: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIResult { + // MARK: Private Helper + + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> APIResult { switch caseId { case 0: return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -64,6 +66,33 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .failure(let param0): + _swift_js_push_int(Int32(param0)) + return Int32(1) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> APIResult { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIResult { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): diff --git a/Sources/JavaScriptKit/BridgeJSInstrincics.swift b/Sources/JavaScriptKit/BridgeJSInstrincics.swift index 5a8f7f01..be6e7b47 100644 --- a/Sources/JavaScriptKit/BridgeJSInstrincics.swift +++ b/Sources/JavaScriptKit/BridgeJSInstrincics.swift @@ -325,6 +325,11 @@ public protocol _BridgedSwiftEnumNoPayload {} /// /// The conformance is automatically synthesized by the BridgeJS code generator. public protocol _BridgedSwiftCaseEnum { + // MARK: ImportTS + @_spi(BridgeJS) consuming func bridgeJSLowerParameter() -> Int32 + @_spi(BridgeJS) static func bridgeJSLiftReturn(_ value: Int32) -> Self + + // MARK: ExportSwift @_spi(BridgeJS) static func bridgeJSLiftParameter(_ value: Int32) -> Self @_spi(BridgeJS) consuming func bridgeJSLowerReturn() -> Int32 } @@ -332,7 +337,12 @@ public protocol _BridgedSwiftCaseEnum { /// A protocol that Swift associated value enum types conform to. /// /// The conformance is automatically synthesized by the BridgeJS code generator. -public protocol _BridgedSwiftAssociatedValueEnum { +public protocol _BridgedSwiftAssociatedValueEnum: _BridgedSwiftTypeLoweredIntoVoidType { + // MARK: ImportTS + @_spi(BridgeJS) consuming func bridgeJSLowerParameter() -> Int32 + @_spi(BridgeJS) static func bridgeJSLiftReturn() -> Self + + // MARK: ExportSwift @_spi(BridgeJS) static func bridgeJSLiftParameter(_ caseId: Int32) -> Self @_spi(BridgeJS) consuming func bridgeJSLowerReturn() -> Void } @@ -340,8 +350,9 @@ public protocol _BridgedSwiftAssociatedValueEnum { extension _BridgedSwiftEnumNoPayload where Self: RawRepresentable, RawValue == String { // MARK: ImportTS @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { rawValue.bridgeJSLowerParameter() } - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ bytesCount: Int32) -> Self { - Self(rawValue: .bridgeJSLiftReturn(bytesCount))! + + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ id: Int32) -> Self { + Self(rawValue: .bridgeJSLiftReturn(id))! } // MARK: ExportSwift @@ -823,20 +834,21 @@ extension Optional where Wrapped == Double { extension Optional where Wrapped: _BridgedSwiftCaseEnum { // MARK: ImportTS - @available( - *, - unavailable, - message: "Optional case enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Void {} + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + switch consume self { + case .none: + return -1 // Sentinel for nil + case .some(let value): + return value.bridgeJSLowerParameter() + } + } - @available( - *, - unavailable, - message: "Optional case enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ wrappedValue: Int32) -> Wrapped? { - return nil + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Wrapped? { + if value == -1 { + return nil + } else { + return Wrapped.bridgeJSLiftReturn(value) + } } // MARK: ExportSwift @@ -890,19 +902,23 @@ extension Optional where Wrapped: _BridgedSwiftTypeLoweredIntoVoidType { extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == String { // MARK: ImportTS - @available( - *, - unavailable, - message: "Optional String raw value enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Void {} + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + switch consume self { + case .none: + return 0 // Sentinel for nil + case .some(let value): + return value.bridgeJSLowerParameter() + } + } - @available( - *, - unavailable, - message: "Optional String raw value enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32) -> Wrapped? { return nil } + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ length: Int32) -> Wrapped? { + if length == 0 { + return nil + } else { + let rawValue = String.bridgeJSLiftReturn(length) + return Wrapped(rawValue: rawValue) + } + } // MARK: ExportSwift @@ -924,20 +940,21 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Int { // MARK: ImportTS - @available( - *, - unavailable, - message: "Optional Int raw value enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Void {} + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + switch consume self { + case .none: + return -1 // Sentinel for nil + case .some(let value): + return value.bridgeJSLowerParameter() + } + } - @available( - *, - unavailable, - message: "Optional Int raw value enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ wrappedValue: Int32) -> Wrapped? { - return nil + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Wrapped? { + if value == -1 { + return nil + } else { + return Wrapped(rawValue: Int(value)) + } } // MARK: ExportSwift @@ -956,20 +973,21 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Bool { // MARK: ImportTS - @available( - *, - unavailable, - message: "Optional Bool raw value enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Void {} + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + switch consume self { + case .none: + return -1 // Sentinel for nil + case .some(let value): + return value.bridgeJSLowerParameter() + } + } - @available( - *, - unavailable, - message: "Optional Bool raw value enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ wrappedValue: Int32) -> Wrapped? { - return nil + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Wrapped? { + if value == -1 { + return nil + } else { + return Wrapped(rawValue: value != 0) + } } // MARK: ExportSwift @@ -988,20 +1006,21 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Float { // MARK: ImportTS - @available( - *, - unavailable, - message: "Optional Float raw value enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Void {} + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Float32 { + switch consume self { + case .none: + return Float32.nan // Sentinel for nil (NaN) + case .some(let value): + return value.bridgeJSLowerParameter() + } + } - @available( - *, - unavailable, - message: "Optional Float raw value enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ wrappedValue: Float32) -> Wrapped? { - return nil + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Float32) -> Wrapped? { + if value.isNaN { + return nil + } else { + return Wrapped(rawValue: Float(value)) + } } // MARK: ExportSwift @@ -1020,20 +1039,21 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Double { // MARK: ImportTS - @available( - *, - unavailable, - message: "Optional Double raw value enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Void {} + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Float64 { + switch consume self { + case .none: + return Float64.nan // Sentinel for nil (NaN) + case .some(let value): + return value.bridgeJSLowerParameter() + } + } - @available( - *, - unavailable, - message: "Optional Double raw value enum types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ wrappedValue: Float64) -> Wrapped? { - return nil + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Float64) -> Wrapped? { + if value.isNaN { + return nil + } else { + return Wrapped(rawValue: Double(value)) + } } // MARK: ExportSwift @@ -1053,21 +1073,27 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres extension Optional where Wrapped: _BridgedSwiftAssociatedValueEnum { // MARK: ImportTS - @available( - *, - unavailable, - message: "Optional associated value enums are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Void { - fatalError("Optional associated value enum bridgeJSLowerParameter is not supported for ImportTS") + + @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + switch consume self { + case .none: + return -1 // Sentinel for nil + case .some(let value): + return value.bridgeJSLowerParameter() + } } - @available( - *, - unavailable, - message: "Optional associated value enums are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ caseId: Int32) -> Wrapped? { return nil } + @_spi(BridgeJS) public static func bridgeJSLiftReturn() -> Wrapped? { + // Read tag from side channel + let tag = _swift_js_pop_param_int32() + if tag == -1 { + return nil + } else { + // Put tag back for the wrapped type's liftReturn to consume + _swift_js_push_int(tag) + return Wrapped.bridgeJSLiftReturn() + } + } // MARK: ExportSwift diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 01956551..168a8c6e 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -859,10 +859,11 @@ enum APIOptionalResult { // MARK: - Protocol Tests -@JS protocol Counter { +@JS protocol DataProcessor { var count: Int { get set } var name: String { get } var optionalTag: String? { get set } + var apiResult: APIResult? { get set } func increment(by amount: Int) func getValue() -> Int func setLabelElements(_ labelPrefix: String, _ labelSuffix: String) @@ -872,56 +873,59 @@ enum APIOptionalResult { func createGreeter() -> Greeter func processOptionalGreeter(_ greeter: Greeter?) -> String func createOptionalGreeter() -> Greeter? + func handleAPIResult(_ result: APIResult) + func getAPIResult() -> APIResult } -@JS class CounterManager { +@JS class DataProcessorManager { - @JS var counter: Counter - @JS var backupCounter: Counter? + @JS var processor: DataProcessor + @JS var backupProcessor: DataProcessor? - @JS init(counter: Counter) { - self.counter = counter - self.backupCounter = nil + @JS init(processor: DataProcessor) { + self.processor = processor + self.backupProcessor = nil } @JS func incrementByAmount(_ amount: Int) { - counter.increment(by: amount) + processor.increment(by: amount) } - @JS func setCounterLabel(_ prefix: String, _ suffix: String) { - counter.setLabelElements(prefix, suffix) + @JS func setProcessorLabel(_ prefix: String, _ suffix: String) { + processor.setLabelElements(prefix, suffix) } - @JS func isCounterEven() -> Bool { - return counter.isEven() + @JS func isProcessorEven() -> Bool { + return processor.isEven() } - @JS func getCounterLabel() -> String { - return counter.getLabel() + @JS func getProcessorLabel() -> String { + return processor.getLabel() } @JS func getCurrentValue() -> Int { - return counter.getValue() + return processor.getValue() } @JS func incrementBoth() { - counter.increment(by: 1) - backupCounter?.increment(by: 1) + processor.increment(by: 1) + backupProcessor?.increment(by: 1) } @JS func getBackupValue() -> Int? { - return backupCounter?.getValue() + return backupProcessor?.getValue() } @JS func hasBackup() -> Bool { - return backupCounter != nil + return backupProcessor != nil } } -@JS class SwiftCounter: Counter { +@JS class SwiftDataProcessor: DataProcessor { @JS var count: Int = 0 - @JS let name: String = "SwiftCounter" + @JS let name: String = "SwiftDataProcessor" @JS var optionalTag: String? = nil + @JS var apiResult: APIResult? = nil private var label: String = "" @JS init() {} @@ -947,23 +951,31 @@ enum APIOptionalResult { } @JS func processGreeter(_ greeter: Greeter) -> String { - return "SwiftCounter processed: \(greeter.greet())" + return "SwiftProcessor processed: \(greeter.greet())" } @JS func createGreeter() -> Greeter { - return Greeter(name: "CounterGreeter") + return Greeter(name: "ProcessorGreeter") } @JS func processOptionalGreeter(_ greeter: Greeter?) -> String { if let greeter = greeter { - return "SwiftCounter processed optional: \(greeter.greet())" + return "SwiftProcessor processed optional: \(greeter.greet())" } else { - return "SwiftCounter received nil" + return "SwiftProcessor received nil" } } @JS func createOptionalGreeter() -> Greeter? { - return Greeter(name: "OptionalCounterGreeter") + return Greeter(name: "OptionalProcessorGreeter") + } + + @JS func handleAPIResult(_ result: APIResult) { + self.apiResult = result + } + + @JS func getAPIResult() -> APIResult { + return apiResult ?? .failure(0) } } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift index 55cde957..58938a94 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift @@ -6,17 +6,17 @@ @_spi(BridgeJS) import JavaScriptKit -struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { +struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { let jsObject: JSObject func increment(by amount: Int) { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_increment") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_increment") func _extern_increment(this: Int32, amount: Int32) _extern_increment(this: Int32(bitPattern: jsObject.id), amount: amount.bridgeJSLowerParameter()) } func getValue() -> Int { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_getValue") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_getValue") func _extern_getValue(this: Int32) -> Int32 let ret = _extern_getValue(this: Int32(bitPattern: jsObject.id)) <<<<<<< HEAD @@ -27,13 +27,13 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { } func setLabelElements(_ labelPrefix: String, _ labelSuffix: String) { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_setLabelElements") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_setLabelElements") func _extern_setLabelElements(this: Int32, labelPrefix: Int32, labelSuffix: Int32) _extern_setLabelElements(this: Int32(bitPattern: jsObject.id), labelPrefix: labelPrefix.bridgeJSLowerParameter(), labelSuffix: labelSuffix.bridgeJSLowerParameter()) } func getLabel() -> String { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_getLabel") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_getLabel") func _extern_getLabel(this: Int32) -> Int32 let ret = _extern_getLabel(this: Int32(bitPattern: jsObject.id)) <<<<<<< HEAD @@ -44,49 +44,62 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { } func isEven() -> Bool { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_isEven") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_isEven") func _extern_isEven(this: Int32) -> Int32 let ret = _extern_isEven(this: Int32(bitPattern: jsObject.id)) return Bool.bridgeJSLiftReturn(ret) } func processGreeter(_ greeter: Greeter) -> String { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_processGreeter") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_processGreeter") func _extern_processGreeter(this: Int32, greeter: UnsafeMutableRawPointer) -> Int32 let ret = _extern_processGreeter(this: Int32(bitPattern: jsObject.id), greeter: greeter.bridgeJSLowerParameter()) return String.bridgeJSLiftReturn(ret) } func createGreeter() -> Greeter { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_createGreeter") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_createGreeter") func _extern_createGreeter(this: Int32) -> UnsafeMutableRawPointer let ret = _extern_createGreeter(this: Int32(bitPattern: jsObject.id)) return Greeter.bridgeJSLiftReturn(ret) } func processOptionalGreeter(_ greeter: Optional) -> String { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_processOptionalGreeter") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_processOptionalGreeter") func _extern_processOptionalGreeter(this: Int32, greeter: UnsafeMutableRawPointer) -> Int32 let ret = _extern_processOptionalGreeter(this: Int32(bitPattern: jsObject.id), greeter: greeter.bridgeJSLowerParameter()) return String.bridgeJSLiftReturn(ret) } func createOptionalGreeter() -> Optional { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_createOptionalGreeter") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_createOptionalGreeter") func _extern_createOptionalGreeter(this: Int32) -> UnsafeMutableRawPointer let ret = _extern_createOptionalGreeter(this: Int32(bitPattern: jsObject.id)) return Optional.bridgeJSLiftReturn(ret) } + func handleAPIResult(_ result: APIResult) { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_handleAPIResult") + func _extern_handleAPIResult(this: Int32, result: Int32) + _extern_handleAPIResult(this: Int32(bitPattern: jsObject.id), result: result.bridgeJSLowerParameter()) + } + + func getAPIResult() -> APIResult { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_getAPIResult") + func _extern_getAPIResult(this: Int32) + _extern_getAPIResult(this: Int32(bitPattern: jsObject.id)) + return APIResult.bridgeJSLiftReturn() + } + var count: Int { get { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_count_get") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_count_get") func _extern_get(this: Int32) -> Int32 let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) return Int.bridgeJSLiftReturn(ret) } set { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_count_set") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_count_set") func _extern_set(this: Int32, value: Int32) _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) } @@ -94,7 +107,7 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { var name: String { get { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_name_get") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_name_get") func _extern_get(this: Int32) -> Int32 let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) return String.bridgeJSLiftReturn(ret) @@ -103,20 +116,34 @@ struct AnyCounter: Counter, _BridgedSwiftProtocolWrapper { var optionalTag: Optional { get { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_optionalTag_get") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalTag_get") func _extern_get(this: Int32) -> Int32 let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) return Optional.bridgeJSLiftReturn(ret) } set { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_Counter_optionalTag_set") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalTag_set") + func _extern_set(this: Int32, value: Int32) + _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + } + } + + var apiResult: Optional { + get { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_apiResult_get") + func _extern_get(this: Int32) + _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturn() + } + set { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_apiResult_set") func _extern_set(this: Int32, value: Int32) _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) } } static func bridgeJSLiftParameter(_ value: Int32) -> Self { - return AnyCounter(jsObject: JSObject(id: UInt32(bitPattern: value))) + return AnyDataProcessor(jsObject: JSObject(id: UInt32(bitPattern: value))) } } @@ -125,13 +152,13 @@ extension Direction: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Direction { - return Direction(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Direction { return Direction(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -168,13 +195,13 @@ extension Status: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Status { - return Status(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Status { return Status(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -213,13 +240,13 @@ extension TSDirection: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> TSDirection { - return TSDirection(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> TSDirection { return TSDirection(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -259,13 +286,13 @@ extension Networking.API.Method: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Networking.API.Method { - return Networking.API.Method(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Networking.API.Method { return Networking.API.Method(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -308,13 +335,13 @@ extension Internal.SupportedMethod: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Internal.SupportedMethod { - return Internal.SupportedMethod(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Internal.SupportedMethod { return Internal.SupportedMethod(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -339,7 +366,7 @@ extension Internal.SupportedMethod: _BridgedSwiftCaseEnum { } extension APIResult: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIResult { + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> APIResult { switch caseId { case 0: return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -358,6 +385,44 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .failure(let param0): + _swift_js_push_int(Int32(param0)) + return Int32(1) + case .flag(let param0): + _swift_js_push_int(param0 ? 1 : 0) + return Int32(2) + case .rate(let param0): + _swift_js_push_f32(param0) + return Int32(3) + case .precise(let param0): + _swift_js_push_f64(param0) + return Int32(4) + case .info: + return Int32(5) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> APIResult { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIResult { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): @@ -385,7 +450,7 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } extension ComplexResult: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> ComplexResult { + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> ComplexResult { switch caseId { case 0: return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -406,6 +471,80 @@ extension ComplexResult: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .error(let param0, let param1): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + _swift_js_push_int(Int32(param1)) + return Int32(1) + case .location(let param0, let param1, let param2): + _swift_js_push_f64(param0) + _swift_js_push_f64(param1) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(2) + case .status(let param0, let param1, let param2): + _swift_js_push_int(param0 ? 1 : 0) + _swift_js_push_int(Int32(param1)) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(3) + case .coordinates(let param0, let param1, let param2): + _swift_js_push_f64(param0) + _swift_js_push_f64(param1) + _swift_js_push_f64(param2) + return Int32(4) + case .comprehensive(let param0, let param1, let param2, let param3, let param4, let param5, let param6, let param7, let param8): + _swift_js_push_int(param0 ? 1 : 0) + _swift_js_push_int(param1 ? 1 : 0) + _swift_js_push_int(Int32(param2)) + _swift_js_push_int(Int32(param3)) + _swift_js_push_f64(param4) + _swift_js_push_f64(param5) + var __bjs_param6 = param6 + __bjs_param6.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + var __bjs_param7 = param7 + __bjs_param7.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + var __bjs_param8 = param8 + __bjs_param8.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(5) + case .info: + return Int32(6) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> ComplexResult { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> ComplexResult { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): @@ -469,7 +608,7 @@ extension ComplexResult: _BridgedSwiftAssociatedValueEnum { } extension Utilities.Result: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> Utilities.Result { + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> Utilities.Result { switch caseId { case 0: return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -482,6 +621,45 @@ extension Utilities.Result: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .failure(let param0, let param1): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + _swift_js_push_int(Int32(param1)) + return Int32(1) + case .status(let param0, let param1, let param2): + _swift_js_push_int(param0 ? 1 : 0) + _swift_js_push_int(Int32(param1)) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(2) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> Utilities.Result { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> Utilities.Result { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): @@ -510,7 +688,7 @@ extension Utilities.Result: _BridgedSwiftAssociatedValueEnum { } extension API.NetworkingResult: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> API.NetworkingResult { + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> API.NetworkingResult { switch caseId { case 0: return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -521,6 +699,37 @@ extension API.NetworkingResult: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .failure(let param0, let param1): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + _swift_js_push_int(Int32(param1)) + return Int32(1) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> API.NetworkingResult { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> API.NetworkingResult { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): @@ -541,7 +750,7 @@ extension API.NetworkingResult: _BridgedSwiftAssociatedValueEnum { } extension APIOptionalResult: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIOptionalResult { + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> APIOptionalResult { switch caseId { case 0: return .success(Optional.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -554,6 +763,66 @@ extension APIOptionalResult: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + let __bjs_isSome_param0 = param0 != nil + if let __bjs_unwrapped_param0 = param0 { + var __bjs_str_param0 = __bjs_unwrapped_param0 + __bjs_str_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + } + _swift_js_push_int(__bjs_isSome_param0 ? 1 : 0) + return Int32(0) + case .failure(let param0, let param1): + let __bjs_isSome_param0 = param0 != nil + if let __bjs_unwrapped_param0 = param0 { + _swift_js_push_int(Int32(__bjs_unwrapped_param0)) + } + _swift_js_push_int(__bjs_isSome_param0 ? 1 : 0) + let __bjs_isSome_param1 = param1 != nil + if let __bjs_unwrapped_param1 = param1 { + _swift_js_push_int(__bjs_unwrapped_param1 ? 1 : 0) + } + _swift_js_push_int(__bjs_isSome_param1 ? 1 : 0) + return Int32(1) + case .status(let param0, let param1, let param2): + let __bjs_isSome_param0 = param0 != nil + if let __bjs_unwrapped_param0 = param0 { + _swift_js_push_int(__bjs_unwrapped_param0 ? 1 : 0) + } + _swift_js_push_int(__bjs_isSome_param0 ? 1 : 0) + let __bjs_isSome_param1 = param1 != nil + if let __bjs_unwrapped_param1 = param1 { + _swift_js_push_int(Int32(__bjs_unwrapped_param1)) + } + _swift_js_push_int(__bjs_isSome_param1 ? 1 : 0) + let __bjs_isSome_param2 = param2 != nil + if let __bjs_unwrapped_param2 = param2 { + var __bjs_str_param2 = __bjs_unwrapped_param2 + __bjs_str_param2.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + } + _swift_js_push_int(__bjs_isSome_param2 ? 1 : 0) + return Int32(2) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> APIOptionalResult { + let caseId = _swift_js_pop_param_int32() + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIOptionalResult { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): @@ -607,13 +876,13 @@ extension StaticCalculator: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> StaticCalculator { - return StaticCalculator(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> StaticCalculator { return StaticCalculator(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -664,13 +933,13 @@ extension StaticPropertyEnum: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> StaticPropertyEnum { - return StaticPropertyEnum(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> StaticPropertyEnum { return StaticPropertyEnum(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -3358,129 +3627,129 @@ extension StaticPropertyHolder: ConvertibleToJSValue, _BridgedSwiftHeapObject { } } -@_expose(wasm, "bjs_CounterManager_init") -@_cdecl("bjs_CounterManager_init") -public func _bjs_CounterManager_init(counter: Int32) -> UnsafeMutableRawPointer { +@_expose(wasm, "bjs_DataProcessorManager_init") +@_cdecl("bjs_DataProcessorManager_init") +public func _bjs_DataProcessorManager_init(processor: Int32) -> UnsafeMutableRawPointer { #if arch(wasm32) - let ret = CounterManager(counter: AnyCounter.bridgeJSLiftParameter(counter)) + let ret = DataProcessorManager(processor: AnyDataProcessor.bridgeJSLiftParameter(processor)) return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_incrementByAmount") -@_cdecl("bjs_CounterManager_incrementByAmount") -public func _bjs_CounterManager_incrementByAmount(_self: UnsafeMutableRawPointer, amount: Int32) -> Void { +@_expose(wasm, "bjs_DataProcessorManager_incrementByAmount") +@_cdecl("bjs_DataProcessorManager_incrementByAmount") +public func _bjs_DataProcessorManager_incrementByAmount(_self: UnsafeMutableRawPointer, amount: Int32) -> Void { #if arch(wasm32) - CounterManager.bridgeJSLiftParameter(_self).incrementByAmount(_: Int.bridgeJSLiftParameter(amount)) + DataProcessorManager.bridgeJSLiftParameter(_self).incrementByAmount(_: Int.bridgeJSLiftParameter(amount)) #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_setCounterLabel") -@_cdecl("bjs_CounterManager_setCounterLabel") -public func _bjs_CounterManager_setCounterLabel(_self: UnsafeMutableRawPointer, prefixBytes: Int32, prefixLength: Int32, suffixBytes: Int32, suffixLength: Int32) -> Void { +@_expose(wasm, "bjs_DataProcessorManager_setProcessorLabel") +@_cdecl("bjs_DataProcessorManager_setProcessorLabel") +public func _bjs_DataProcessorManager_setProcessorLabel(_self: UnsafeMutableRawPointer, prefixBytes: Int32, prefixLength: Int32, suffixBytes: Int32, suffixLength: Int32) -> Void { #if arch(wasm32) - CounterManager.bridgeJSLiftParameter(_self).setCounterLabel(_: String.bridgeJSLiftParameter(prefixBytes, prefixLength), _: String.bridgeJSLiftParameter(suffixBytes, suffixLength)) + DataProcessorManager.bridgeJSLiftParameter(_self).setProcessorLabel(_: String.bridgeJSLiftParameter(prefixBytes, prefixLength), _: String.bridgeJSLiftParameter(suffixBytes, suffixLength)) #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_isCounterEven") -@_cdecl("bjs_CounterManager_isCounterEven") -public func _bjs_CounterManager_isCounterEven(_self: UnsafeMutableRawPointer) -> Int32 { +@_expose(wasm, "bjs_DataProcessorManager_isProcessorEven") +@_cdecl("bjs_DataProcessorManager_isProcessorEven") +public func _bjs_DataProcessorManager_isProcessorEven(_self: UnsafeMutableRawPointer) -> Int32 { #if arch(wasm32) - let ret = CounterManager.bridgeJSLiftParameter(_self).isCounterEven() + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).isProcessorEven() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_getCounterLabel") -@_cdecl("bjs_CounterManager_getCounterLabel") -public func _bjs_CounterManager_getCounterLabel(_self: UnsafeMutableRawPointer) -> Void { +@_expose(wasm, "bjs_DataProcessorManager_getProcessorLabel") +@_cdecl("bjs_DataProcessorManager_getProcessorLabel") +public func _bjs_DataProcessorManager_getProcessorLabel(_self: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - let ret = CounterManager.bridgeJSLiftParameter(_self).getCounterLabel() + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).getProcessorLabel() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_getCurrentValue") -@_cdecl("bjs_CounterManager_getCurrentValue") -public func _bjs_CounterManager_getCurrentValue(_self: UnsafeMutableRawPointer) -> Int32 { +@_expose(wasm, "bjs_DataProcessorManager_getCurrentValue") +@_cdecl("bjs_DataProcessorManager_getCurrentValue") +public func _bjs_DataProcessorManager_getCurrentValue(_self: UnsafeMutableRawPointer) -> Int32 { #if arch(wasm32) - let ret = CounterManager.bridgeJSLiftParameter(_self).getCurrentValue() + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).getCurrentValue() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_incrementBoth") -@_cdecl("bjs_CounterManager_incrementBoth") -public func _bjs_CounterManager_incrementBoth(_self: UnsafeMutableRawPointer) -> Void { +@_expose(wasm, "bjs_DataProcessorManager_incrementBoth") +@_cdecl("bjs_DataProcessorManager_incrementBoth") +public func _bjs_DataProcessorManager_incrementBoth(_self: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - CounterManager.bridgeJSLiftParameter(_self).incrementBoth() + DataProcessorManager.bridgeJSLiftParameter(_self).incrementBoth() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_getBackupValue") -@_cdecl("bjs_CounterManager_getBackupValue") -public func _bjs_CounterManager_getBackupValue(_self: UnsafeMutableRawPointer) -> Void { +@_expose(wasm, "bjs_DataProcessorManager_getBackupValue") +@_cdecl("bjs_DataProcessorManager_getBackupValue") +public func _bjs_DataProcessorManager_getBackupValue(_self: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - let ret = CounterManager.bridgeJSLiftParameter(_self).getBackupValue() + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).getBackupValue() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_hasBackup") -@_cdecl("bjs_CounterManager_hasBackup") -public func _bjs_CounterManager_hasBackup(_self: UnsafeMutableRawPointer) -> Int32 { +@_expose(wasm, "bjs_DataProcessorManager_hasBackup") +@_cdecl("bjs_DataProcessorManager_hasBackup") +public func _bjs_DataProcessorManager_hasBackup(_self: UnsafeMutableRawPointer) -> Int32 { #if arch(wasm32) - let ret = CounterManager.bridgeJSLiftParameter(_self).hasBackup() + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).hasBackup() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_counter_get") -@_cdecl("bjs_CounterManager_counter_get") -public func _bjs_CounterManager_counter_get(_self: UnsafeMutableRawPointer) -> Int32 { +@_expose(wasm, "bjs_DataProcessorManager_processor_get") +@_cdecl("bjs_DataProcessorManager_processor_get") +public func _bjs_DataProcessorManager_processor_get(_self: UnsafeMutableRawPointer) -> Int32 { #if arch(wasm32) - let ret = CounterManager.bridgeJSLiftParameter(_self).counter as! AnyCounter + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).processor as! AnyDataProcessor return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_counter_set") -@_cdecl("bjs_CounterManager_counter_set") -public func _bjs_CounterManager_counter_set(_self: UnsafeMutableRawPointer, value: Int32) -> Void { +@_expose(wasm, "bjs_DataProcessorManager_processor_set") +@_cdecl("bjs_DataProcessorManager_processor_set") +public func _bjs_DataProcessorManager_processor_set(_self: UnsafeMutableRawPointer, value: Int32) -> Void { #if arch(wasm32) - CounterManager.bridgeJSLiftParameter(_self).counter = AnyCounter.bridgeJSLiftParameter(value) + DataProcessorManager.bridgeJSLiftParameter(_self).processor = AnyDataProcessor.bridgeJSLiftParameter(value) #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_backupCounter_get") -@_cdecl("bjs_CounterManager_backupCounter_get") -public func _bjs_CounterManager_backupCounter_get(_self: UnsafeMutableRawPointer) -> Void { +@_expose(wasm, "bjs_DataProcessorManager_backupProcessor_get") +@_cdecl("bjs_DataProcessorManager_backupProcessor_get") +public func _bjs_DataProcessorManager_backupProcessor_get(_self: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - let ret = CounterManager.bridgeJSLiftParameter(_self).backupCounter.flatMap { - $0 as? AnyCounter + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).backupProcessor.flatMap { + $0 as? AnyDataProcessor } return ret.bridgeJSLowerReturn() #else @@ -3488,213 +3757,255 @@ public func _bjs_CounterManager_backupCounter_get(_self: UnsafeMutableRawPointer #endif } -@_expose(wasm, "bjs_CounterManager_backupCounter_set") -@_cdecl("bjs_CounterManager_backupCounter_set") -public func _bjs_CounterManager_backupCounter_set(_self: UnsafeMutableRawPointer, valueIsSome: Int32, valueValue: Int32) -> Void { +@_expose(wasm, "bjs_DataProcessorManager_backupProcessor_set") +@_cdecl("bjs_DataProcessorManager_backupProcessor_set") +public func _bjs_DataProcessorManager_backupProcessor_set(_self: UnsafeMutableRawPointer, valueIsSome: Int32, valueValue: Int32) -> Void { #if arch(wasm32) - CounterManager.bridgeJSLiftParameter(_self).backupCounter = Optional.bridgeJSLiftParameter(valueIsSome, valueValue) + DataProcessorManager.bridgeJSLiftParameter(_self).backupProcessor = Optional.bridgeJSLiftParameter(valueIsSome, valueValue) #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_CounterManager_deinit") -@_cdecl("bjs_CounterManager_deinit") -public func _bjs_CounterManager_deinit(pointer: UnsafeMutableRawPointer) { - Unmanaged.fromOpaque(pointer).release() +@_expose(wasm, "bjs_DataProcessorManager_deinit") +@_cdecl("bjs_DataProcessorManager_deinit") +public func _bjs_DataProcessorManager_deinit(pointer: UnsafeMutableRawPointer) { + Unmanaged.fromOpaque(pointer).release() } -extension CounterManager: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension DataProcessorManager: ConvertibleToJSValue, _BridgedSwiftHeapObject { var jsValue: JSValue { #if arch(wasm32) - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_CounterManager_wrap") - func _bjs_CounterManager_wrap(_: UnsafeMutableRawPointer) -> Int32 + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessorManager_wrap") + func _bjs_DataProcessorManager_wrap(_: UnsafeMutableRawPointer) -> Int32 #else - func _bjs_CounterManager_wrap(_: UnsafeMutableRawPointer) -> Int32 { + func _bjs_DataProcessorManager_wrap(_: UnsafeMutableRawPointer) -> Int32 { fatalError("Only available on WebAssembly") } #endif - return .object(JSObject(id: UInt32(bitPattern: _bjs_CounterManager_wrap(Unmanaged.passRetained(self).toOpaque())))) + return .object(JSObject(id: UInt32(bitPattern: _bjs_DataProcessorManager_wrap(Unmanaged.passRetained(self).toOpaque())))) } } -@_expose(wasm, "bjs_SwiftCounter_init") -@_cdecl("bjs_SwiftCounter_init") -public func _bjs_SwiftCounter_init() -> UnsafeMutableRawPointer { +@_expose(wasm, "bjs_SwiftDataProcessor_init") +@_cdecl("bjs_SwiftDataProcessor_init") +public func _bjs_SwiftDataProcessor_init() -> UnsafeMutableRawPointer { #if arch(wasm32) - let ret = SwiftCounter() + let ret = SwiftDataProcessor() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_increment") -@_cdecl("bjs_SwiftCounter_increment") -public func _bjs_SwiftCounter_increment(_self: UnsafeMutableRawPointer, amount: Int32) -> Void { +@_expose(wasm, "bjs_SwiftDataProcessor_increment") +@_cdecl("bjs_SwiftDataProcessor_increment") +public func _bjs_SwiftDataProcessor_increment(_self: UnsafeMutableRawPointer, amount: Int32) -> Void { #if arch(wasm32) - SwiftCounter.bridgeJSLiftParameter(_self).increment(by: Int.bridgeJSLiftParameter(amount)) + SwiftDataProcessor.bridgeJSLiftParameter(_self).increment(by: Int.bridgeJSLiftParameter(amount)) #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_getValue") -@_cdecl("bjs_SwiftCounter_getValue") -public func _bjs_SwiftCounter_getValue(_self: UnsafeMutableRawPointer) -> Int32 { +@_expose(wasm, "bjs_SwiftDataProcessor_getValue") +@_cdecl("bjs_SwiftDataProcessor_getValue") +public func _bjs_SwiftDataProcessor_getValue(_self: UnsafeMutableRawPointer) -> Int32 { #if arch(wasm32) - let ret = SwiftCounter.bridgeJSLiftParameter(_self).getValue() + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).getValue() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_setLabelElements") -@_cdecl("bjs_SwiftCounter_setLabelElements") -public func _bjs_SwiftCounter_setLabelElements(_self: UnsafeMutableRawPointer, labelPrefixBytes: Int32, labelPrefixLength: Int32, labelSuffixBytes: Int32, labelSuffixLength: Int32) -> Void { +@_expose(wasm, "bjs_SwiftDataProcessor_setLabelElements") +@_cdecl("bjs_SwiftDataProcessor_setLabelElements") +public func _bjs_SwiftDataProcessor_setLabelElements(_self: UnsafeMutableRawPointer, labelPrefixBytes: Int32, labelPrefixLength: Int32, labelSuffixBytes: Int32, labelSuffixLength: Int32) -> Void { #if arch(wasm32) - SwiftCounter.bridgeJSLiftParameter(_self).setLabelElements(_: String.bridgeJSLiftParameter(labelPrefixBytes, labelPrefixLength), _: String.bridgeJSLiftParameter(labelSuffixBytes, labelSuffixLength)) + SwiftDataProcessor.bridgeJSLiftParameter(_self).setLabelElements(_: String.bridgeJSLiftParameter(labelPrefixBytes, labelPrefixLength), _: String.bridgeJSLiftParameter(labelSuffixBytes, labelSuffixLength)) #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_getLabel") -@_cdecl("bjs_SwiftCounter_getLabel") -public func _bjs_SwiftCounter_getLabel(_self: UnsafeMutableRawPointer) -> Void { +@_expose(wasm, "bjs_SwiftDataProcessor_getLabel") +@_cdecl("bjs_SwiftDataProcessor_getLabel") +public func _bjs_SwiftDataProcessor_getLabel(_self: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - let ret = SwiftCounter.bridgeJSLiftParameter(_self).getLabel() + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).getLabel() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_isEven") -@_cdecl("bjs_SwiftCounter_isEven") -public func _bjs_SwiftCounter_isEven(_self: UnsafeMutableRawPointer) -> Int32 { +@_expose(wasm, "bjs_SwiftDataProcessor_isEven") +@_cdecl("bjs_SwiftDataProcessor_isEven") +public func _bjs_SwiftDataProcessor_isEven(_self: UnsafeMutableRawPointer) -> Int32 { #if arch(wasm32) - let ret = SwiftCounter.bridgeJSLiftParameter(_self).isEven() + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).isEven() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_processGreeter") -@_cdecl("bjs_SwiftCounter_processGreeter") -public func _bjs_SwiftCounter_processGreeter(_self: UnsafeMutableRawPointer, greeter: UnsafeMutableRawPointer) -> Void { +@_expose(wasm, "bjs_SwiftDataProcessor_processGreeter") +@_cdecl("bjs_SwiftDataProcessor_processGreeter") +public func _bjs_SwiftDataProcessor_processGreeter(_self: UnsafeMutableRawPointer, greeter: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - let ret = SwiftCounter.bridgeJSLiftParameter(_self).processGreeter(_: Greeter.bridgeJSLiftParameter(greeter)) + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).processGreeter(_: Greeter.bridgeJSLiftParameter(greeter)) return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_createGreeter") -@_cdecl("bjs_SwiftCounter_createGreeter") -public func _bjs_SwiftCounter_createGreeter(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { +@_expose(wasm, "bjs_SwiftDataProcessor_createGreeter") +@_cdecl("bjs_SwiftDataProcessor_createGreeter") +public func _bjs_SwiftDataProcessor_createGreeter(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { #if arch(wasm32) - let ret = SwiftCounter.bridgeJSLiftParameter(_self).createGreeter() + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).createGreeter() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_processOptionalGreeter") -@_cdecl("bjs_SwiftCounter_processOptionalGreeter") -public func _bjs_SwiftCounter_processOptionalGreeter(_self: UnsafeMutableRawPointer, greeterIsSome: Int32, greeterValue: UnsafeMutableRawPointer) -> Void { +@_expose(wasm, "bjs_SwiftDataProcessor_processOptionalGreeter") +@_cdecl("bjs_SwiftDataProcessor_processOptionalGreeter") +public func _bjs_SwiftDataProcessor_processOptionalGreeter(_self: UnsafeMutableRawPointer, greeterIsSome: Int32, greeterValue: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - let ret = SwiftCounter.bridgeJSLiftParameter(_self).processOptionalGreeter(_: Optional.bridgeJSLiftParameter(greeterIsSome, greeterValue)) + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).processOptionalGreeter(_: Optional.bridgeJSLiftParameter(greeterIsSome, greeterValue)) return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_createOptionalGreeter") -@_cdecl("bjs_SwiftCounter_createOptionalGreeter") -public func _bjs_SwiftCounter_createOptionalGreeter(_self: UnsafeMutableRawPointer) -> Void { +@_expose(wasm, "bjs_SwiftDataProcessor_createOptionalGreeter") +@_cdecl("bjs_SwiftDataProcessor_createOptionalGreeter") +public func _bjs_SwiftDataProcessor_createOptionalGreeter(_self: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - let ret = SwiftCounter.bridgeJSLiftParameter(_self).createOptionalGreeter() + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).createOptionalGreeter() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_count_get") -@_cdecl("bjs_SwiftCounter_count_get") -public func _bjs_SwiftCounter_count_get(_self: UnsafeMutableRawPointer) -> Int32 { +@_expose(wasm, "bjs_SwiftDataProcessor_handleAPIResult") +@_cdecl("bjs_SwiftDataProcessor_handleAPIResult") +public func _bjs_SwiftDataProcessor_handleAPIResult(_self: UnsafeMutableRawPointer, result: Int32) -> Void { + #if arch(wasm32) + SwiftDataProcessor.bridgeJSLiftParameter(_self).handleAPIResult(_: APIResult.bridgeJSLiftParameter(result)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_getAPIResult") +@_cdecl("bjs_SwiftDataProcessor_getAPIResult") +public func _bjs_SwiftDataProcessor_getAPIResult(_self: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - let ret = SwiftCounter.bridgeJSLiftParameter(_self).count + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).getAPIResult() return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_count_set") -@_cdecl("bjs_SwiftCounter_count_set") -public func _bjs_SwiftCounter_count_set(_self: UnsafeMutableRawPointer, value: Int32) -> Void { +@_expose(wasm, "bjs_SwiftDataProcessor_count_get") +@_cdecl("bjs_SwiftDataProcessor_count_get") +public func _bjs_SwiftDataProcessor_count_get(_self: UnsafeMutableRawPointer) -> Int32 { #if arch(wasm32) - SwiftCounter.bridgeJSLiftParameter(_self).count = Int.bridgeJSLiftParameter(value) + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).count + return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_name_get") -@_cdecl("bjs_SwiftCounter_name_get") -public func _bjs_SwiftCounter_name_get(_self: UnsafeMutableRawPointer) -> Void { +@_expose(wasm, "bjs_SwiftDataProcessor_count_set") +@_cdecl("bjs_SwiftDataProcessor_count_set") +public func _bjs_SwiftDataProcessor_count_set(_self: UnsafeMutableRawPointer, value: Int32) -> Void { #if arch(wasm32) - let ret = SwiftCounter.bridgeJSLiftParameter(_self).name + SwiftDataProcessor.bridgeJSLiftParameter(_self).count = Int.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_name_get") +@_cdecl("bjs_SwiftDataProcessor_name_get") +public func _bjs_SwiftDataProcessor_name_get(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).name return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_optionalTag_get") -@_cdecl("bjs_SwiftCounter_optionalTag_get") -public func _bjs_SwiftCounter_optionalTag_get(_self: UnsafeMutableRawPointer) -> Void { +@_expose(wasm, "bjs_SwiftDataProcessor_optionalTag_get") +@_cdecl("bjs_SwiftDataProcessor_optionalTag_get") +public func _bjs_SwiftDataProcessor_optionalTag_get(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).optionalTag + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_optionalTag_set") +@_cdecl("bjs_SwiftDataProcessor_optionalTag_set") +public func _bjs_SwiftDataProcessor_optionalTag_set(_self: UnsafeMutableRawPointer, valueIsSome: Int32, valueBytes: Int32, valueLength: Int32) -> Void { + #if arch(wasm32) + SwiftDataProcessor.bridgeJSLiftParameter(_self).optionalTag = Optional.bridgeJSLiftParameter(valueIsSome, valueBytes, valueLength) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_apiResult_get") +@_cdecl("bjs_SwiftDataProcessor_apiResult_get") +public func _bjs_SwiftDataProcessor_apiResult_get(_self: UnsafeMutableRawPointer) -> Void { #if arch(wasm32) - let ret = SwiftCounter.bridgeJSLiftParameter(_self).optionalTag + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).apiResult return ret.bridgeJSLowerReturn() #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_optionalTag_set") -@_cdecl("bjs_SwiftCounter_optionalTag_set") -public func _bjs_SwiftCounter_optionalTag_set(_self: UnsafeMutableRawPointer, valueIsSome: Int32, valueBytes: Int32, valueLength: Int32) -> Void { +@_expose(wasm, "bjs_SwiftDataProcessor_apiResult_set") +@_cdecl("bjs_SwiftDataProcessor_apiResult_set") +public func _bjs_SwiftDataProcessor_apiResult_set(_self: UnsafeMutableRawPointer, valueIsSome: Int32, valueCaseId: Int32) -> Void { #if arch(wasm32) - SwiftCounter.bridgeJSLiftParameter(_self).optionalTag = Optional.bridgeJSLiftParameter(valueIsSome, valueBytes, valueLength) + SwiftDataProcessor.bridgeJSLiftParameter(_self).apiResult = Optional.bridgeJSLiftParameter(valueIsSome, valueCaseId) #else fatalError("Only available on WebAssembly") #endif } -@_expose(wasm, "bjs_SwiftCounter_deinit") -@_cdecl("bjs_SwiftCounter_deinit") -public func _bjs_SwiftCounter_deinit(pointer: UnsafeMutableRawPointer) { - Unmanaged.fromOpaque(pointer).release() +@_expose(wasm, "bjs_SwiftDataProcessor_deinit") +@_cdecl("bjs_SwiftDataProcessor_deinit") +public func _bjs_SwiftDataProcessor_deinit(pointer: UnsafeMutableRawPointer) { + Unmanaged.fromOpaque(pointer).release() } -extension SwiftCounter: ConvertibleToJSValue, _BridgedSwiftHeapObject { +extension SwiftDataProcessor: ConvertibleToJSValue, _BridgedSwiftHeapObject { var jsValue: JSValue { #if arch(wasm32) - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_SwiftCounter_wrap") - func _bjs_SwiftCounter_wrap(_: UnsafeMutableRawPointer) -> Int32 + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_SwiftDataProcessor_wrap") + func _bjs_SwiftDataProcessor_wrap(_: UnsafeMutableRawPointer) -> Int32 #else - func _bjs_SwiftCounter_wrap(_: UnsafeMutableRawPointer) -> Int32 { + func _bjs_SwiftDataProcessor_wrap(_: UnsafeMutableRawPointer) -> Int32 { fatalError("Only available on WebAssembly") } #endif - return .object(JSObject(id: UInt32(bitPattern: _bjs_SwiftCounter_wrap(Unmanaged.passRetained(self).toOpaque())))) + return .object(JSObject(id: UInt32(bitPattern: _bjs_SwiftDataProcessor_wrap(Unmanaged.passRetained(self).toOpaque())))) } } \ No newline at end of file diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json index f97beee6..cc380749 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json @@ -1165,7 +1165,7 @@ }, { "constructor" : { - "abiName" : "bjs_CounterManager_init", + "abiName" : "bjs_DataProcessorManager_init", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1173,11 +1173,11 @@ }, "parameters" : [ { - "label" : "counter", - "name" : "counter", + "label" : "processor", + "name" : "processor", "type" : { "swiftProtocol" : { - "_0" : "Counter" + "_0" : "DataProcessor" } } } @@ -1185,7 +1185,7 @@ }, "methods" : [ { - "abiName" : "bjs_CounterManager_incrementByAmount", + "abiName" : "bjs_DataProcessorManager_incrementByAmount", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1210,13 +1210,13 @@ } }, { - "abiName" : "bjs_CounterManager_setCounterLabel", + "abiName" : "bjs_DataProcessorManager_setProcessorLabel", "effects" : { "isAsync" : false, "isStatic" : false, "isThrows" : false }, - "name" : "setCounterLabel", + "name" : "setProcessorLabel", "parameters" : [ { "label" : "_", @@ -1244,13 +1244,13 @@ } }, { - "abiName" : "bjs_CounterManager_isCounterEven", + "abiName" : "bjs_DataProcessorManager_isProcessorEven", "effects" : { "isAsync" : false, "isStatic" : false, "isThrows" : false }, - "name" : "isCounterEven", + "name" : "isProcessorEven", "parameters" : [ ], @@ -1261,13 +1261,13 @@ } }, { - "abiName" : "bjs_CounterManager_getCounterLabel", + "abiName" : "bjs_DataProcessorManager_getProcessorLabel", "effects" : { "isAsync" : false, "isStatic" : false, "isThrows" : false }, - "name" : "getCounterLabel", + "name" : "getProcessorLabel", "parameters" : [ ], @@ -1278,7 +1278,7 @@ } }, { - "abiName" : "bjs_CounterManager_getCurrentValue", + "abiName" : "bjs_DataProcessorManager_getCurrentValue", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1295,7 +1295,7 @@ } }, { - "abiName" : "bjs_CounterManager_incrementBoth", + "abiName" : "bjs_DataProcessorManager_incrementBoth", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1312,7 +1312,7 @@ } }, { - "abiName" : "bjs_CounterManager_getBackupValue", + "abiName" : "bjs_DataProcessorManager_getBackupValue", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1333,7 +1333,7 @@ } }, { - "abiName" : "bjs_CounterManager_hasBackup", + "abiName" : "bjs_DataProcessorManager_hasBackup", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1350,38 +1350,38 @@ } } ], - "name" : "CounterManager", + "name" : "DataProcessorManager", "properties" : [ { "isReadonly" : false, "isStatic" : false, - "name" : "counter", + "name" : "processor", "type" : { "swiftProtocol" : { - "_0" : "Counter" + "_0" : "DataProcessor" } } }, { "isReadonly" : false, "isStatic" : false, - "name" : "backupCounter", + "name" : "backupProcessor", "type" : { "optional" : { "_0" : { "swiftProtocol" : { - "_0" : "Counter" + "_0" : "DataProcessor" } } } } } ], - "swiftCallName" : "CounterManager" + "swiftCallName" : "DataProcessorManager" }, { "constructor" : { - "abiName" : "bjs_SwiftCounter_init", + "abiName" : "bjs_SwiftDataProcessor_init", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1393,7 +1393,7 @@ }, "methods" : [ { - "abiName" : "bjs_SwiftCounter_increment", + "abiName" : "bjs_SwiftDataProcessor_increment", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1418,7 +1418,7 @@ } }, { - "abiName" : "bjs_SwiftCounter_getValue", + "abiName" : "bjs_SwiftDataProcessor_getValue", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1435,7 +1435,7 @@ } }, { - "abiName" : "bjs_SwiftCounter_setLabelElements", + "abiName" : "bjs_SwiftDataProcessor_setLabelElements", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1469,7 +1469,7 @@ } }, { - "abiName" : "bjs_SwiftCounter_getLabel", + "abiName" : "bjs_SwiftDataProcessor_getLabel", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1486,7 +1486,7 @@ } }, { - "abiName" : "bjs_SwiftCounter_isEven", + "abiName" : "bjs_SwiftDataProcessor_isEven", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1503,7 +1503,7 @@ } }, { - "abiName" : "bjs_SwiftCounter_processGreeter", + "abiName" : "bjs_SwiftDataProcessor_processGreeter", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1528,7 +1528,7 @@ } }, { - "abiName" : "bjs_SwiftCounter_createGreeter", + "abiName" : "bjs_SwiftDataProcessor_createGreeter", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1545,7 +1545,7 @@ } }, { - "abiName" : "bjs_SwiftCounter_processOptionalGreeter", + "abiName" : "bjs_SwiftDataProcessor_processOptionalGreeter", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1574,7 +1574,7 @@ } }, { - "abiName" : "bjs_SwiftCounter_createOptionalGreeter", + "abiName" : "bjs_SwiftDataProcessor_createOptionalGreeter", "effects" : { "isAsync" : false, "isStatic" : false, @@ -1593,9 +1593,51 @@ } } } + }, + { + "abiName" : "bjs_SwiftDataProcessor_handleAPIResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "handleAPIResult", + "parameters" : [ + { + "label" : "_", + "name" : "result", + "type" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_SwiftDataProcessor_getAPIResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getAPIResult", + "parameters" : [ + + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } } ], - "name" : "SwiftCounter", + "name" : "SwiftDataProcessor", "properties" : [ { "isReadonly" : false, @@ -1630,9 +1672,23 @@ } } } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "apiResult", + "type" : { + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + } } ], - "swiftCallName" : "SwiftCounter" + "swiftCallName" : "SwiftDataProcessor" } ], "enums" : [ @@ -5911,7 +5967,7 @@ { "methods" : [ { - "abiName" : "bjs_Counter_increment", + "abiName" : "bjs_DataProcessor_increment", "effects" : { "isAsync" : false, "isStatic" : false, @@ -5936,7 +5992,7 @@ } }, { - "abiName" : "bjs_Counter_getValue", + "abiName" : "bjs_DataProcessor_getValue", "effects" : { "isAsync" : false, "isStatic" : false, @@ -5953,7 +6009,7 @@ } }, { - "abiName" : "bjs_Counter_setLabelElements", + "abiName" : "bjs_DataProcessor_setLabelElements", "effects" : { "isAsync" : false, "isStatic" : false, @@ -5987,7 +6043,7 @@ } }, { - "abiName" : "bjs_Counter_getLabel", + "abiName" : "bjs_DataProcessor_getLabel", "effects" : { "isAsync" : false, "isStatic" : false, @@ -6004,7 +6060,7 @@ } }, { - "abiName" : "bjs_Counter_isEven", + "abiName" : "bjs_DataProcessor_isEven", "effects" : { "isAsync" : false, "isStatic" : false, @@ -6021,7 +6077,7 @@ } }, { - "abiName" : "bjs_Counter_processGreeter", + "abiName" : "bjs_DataProcessor_processGreeter", "effects" : { "isAsync" : false, "isStatic" : false, @@ -6046,7 +6102,7 @@ } }, { - "abiName" : "bjs_Counter_createGreeter", + "abiName" : "bjs_DataProcessor_createGreeter", "effects" : { "isAsync" : false, "isStatic" : false, @@ -6063,7 +6119,7 @@ } }, { - "abiName" : "bjs_Counter_processOptionalGreeter", + "abiName" : "bjs_DataProcessor_processOptionalGreeter", "effects" : { "isAsync" : false, "isStatic" : false, @@ -6092,7 +6148,7 @@ } }, { - "abiName" : "bjs_Counter_createOptionalGreeter", + "abiName" : "bjs_DataProcessor_createOptionalGreeter", "effects" : { "isAsync" : false, "isStatic" : false, @@ -6111,9 +6167,51 @@ } } } + }, + { + "abiName" : "bjs_DataProcessor_handleAPIResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "handleAPIResult", + "parameters" : [ + { + "label" : "_", + "name" : "result", + "type" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_DataProcessor_getAPIResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getAPIResult", + "parameters" : [ + + ], + "returnType" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } } ], - "name" : "Counter", + "name" : "DataProcessor", "properties" : [ { "isReadonly" : false, @@ -6145,6 +6243,19 @@ } } } + }, + { + "isReadonly" : false, + "name" : "apiResult", + "type" : { + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + } } ] } diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index 73bc7279..cb67a6a7 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -809,160 +809,185 @@ function setupTestGlobals(global) { /** @param {import('./../.build/plugins/PackageToJS/outputs/PackageTests/bridge-js.d.ts').Exports} exports */ function testProtocolSupport(exports) { - let counterValue = 0; - let counterLabel = ""; - const jsCounter = { + let processorValue = 0; + let processorLabel = ""; + let apiResultValue = null; + const jsProcessor = { count: 0, - name: "JSCounter", + name: "JSProcessor", optionalTag: null, - increment(amount) { counterValue += amount; this.count += amount; }, - getValue() { return counterValue; }, - setLabelElements(labelPrefix, labelSuffix) { counterLabel = labelPrefix + labelSuffix; }, - getLabel() { return counterLabel; }, - isEven() { return counterValue % 2 === 0; }, - processGreeter(greeter) { return `JSCounter processed: ${greeter.greet()}`; }, - createGreeter() { return new exports.Greeter("JSCounterGreeter"); }, + apiResult: null, + increment(amount) { processorValue += amount; this.count += amount; }, + getValue() { return processorValue; }, + setLabelElements(labelPrefix, labelSuffix) { processorLabel = labelPrefix + labelSuffix; }, + getLabel() { return processorLabel; }, + isEven() { return processorValue % 2 === 0; }, + processGreeter(greeter) { return `JSProcessor processed: ${greeter.greet()}`; }, + createGreeter() { return new exports.Greeter("JSProcessorGreeter"); }, processOptionalGreeter(greeter) { - return greeter ? `JSCounter processed optional: ${greeter.greet()}` : "JSCounter received null"; + return greeter ? `JSProcessor processed optional: ${greeter.greet()}` : "JSProcessor received null"; }, - createOptionalGreeter() { return new exports.Greeter("JSOptionalGreeter"); } + createOptionalGreeter() { return new exports.Greeter("JSOptionalGreeter"); }, + handleAPIResult(result) { apiResultValue = result; }, + getAPIResult() { return apiResultValue; } }; - const manager = new exports.CounterManager(jsCounter); + const manager = new exports.DataProcessorManager(jsProcessor); - assert.equal(jsCounter.count, 0); - assert.equal(jsCounter.name, "JSCounter"); + assert.equal(jsProcessor.count, 0); + assert.equal(jsProcessor.name, "JSProcessor"); manager.incrementByAmount(4); assert.equal(manager.getCurrentValue(), 4); - assert.equal(jsCounter.count, 4); + assert.equal(jsProcessor.count, 4); - manager.setCounterLabel("Test", "Label"); - assert.equal(manager.getCounterLabel(), "TestLabel"); - assert.equal(jsCounter.getLabel(), "TestLabel"); + manager.setProcessorLabel("Test", "Label"); + assert.equal(manager.getProcessorLabel(), "TestLabel"); + assert.equal(jsProcessor.getLabel(), "TestLabel"); - assert.equal(manager.isCounterEven(), true); + assert.equal(manager.isProcessorEven(), true); manager.incrementByAmount(1); - assert.equal(manager.isCounterEven(), false); - assert.equal(jsCounter.isEven(), false); + assert.equal(manager.isProcessorEven(), false); + assert.equal(jsProcessor.isEven(), false); - jsCounter.increment(3); - assert.equal(jsCounter.getValue(), 8); + jsProcessor.increment(3); + assert.equal(jsProcessor.getValue(), 8); manager.release(); - const swiftCounter = new exports.SwiftCounter(); - const swiftManager = new exports.CounterManager(swiftCounter); + const swiftProcessor = new exports.SwiftDataProcessor(); + const swiftManager = new exports.DataProcessorManager(swiftProcessor); - assert.equal(swiftCounter.count, 0); - assert.equal(swiftCounter.name, "SwiftCounter"); + assert.equal(swiftProcessor.count, 0); + assert.equal(swiftProcessor.name, "SwiftDataProcessor"); swiftManager.incrementByAmount(10); assert.equal(swiftManager.getCurrentValue(), 10); - assert.equal(swiftCounter.count, 10); + assert.equal(swiftProcessor.count, 10); - swiftManager.setCounterLabel("Swift", "Label"); - assert.equal(swiftManager.getCounterLabel(), "SwiftLabel"); + swiftManager.setProcessorLabel("Swift", "Label"); + assert.equal(swiftManager.getProcessorLabel(), "SwiftLabel"); - swiftCounter.increment(5); - assert.equal(swiftCounter.getValue(), 15); - assert.equal(swiftCounter.count, 15); + swiftProcessor.increment(5); + assert.equal(swiftProcessor.getValue(), 15); + assert.equal(swiftProcessor.count, 15); - swiftCounter.count = 100; - assert.equal(swiftCounter.count, 100); - assert.equal(swiftCounter.getValue(), 100); + swiftProcessor.count = 100; + assert.equal(swiftProcessor.count, 100); + assert.equal(swiftProcessor.getValue(), 100); const testGreeter = new exports.Greeter("TestUser"); - const jsResult = jsCounter.processGreeter(testGreeter); - assert.equal(jsResult, "JSCounter processed: Hello, TestUser!"); + const jsResult = jsProcessor.processGreeter(testGreeter); + assert.equal(jsResult, "JSProcessor processed: Hello, TestUser!"); - const swiftResult = swiftCounter.processGreeter(testGreeter); - assert.equal(swiftResult, "SwiftCounter processed: Hello, TestUser!"); + const swiftResult = swiftProcessor.processGreeter(testGreeter); + assert.equal(swiftResult, "SwiftProcessor processed: Hello, TestUser!"); // Test swiftHeapObject return from protocol methods - const jsCreatedGreeter = jsCounter.createGreeter(); - assert.equal(jsCreatedGreeter.name, "JSCounterGreeter"); - assert.equal(jsCreatedGreeter.greet(), "Hello, JSCounterGreeter!"); + const jsCreatedGreeter = jsProcessor.createGreeter(); + assert.equal(jsCreatedGreeter.name, "JSProcessorGreeter"); + assert.equal(jsCreatedGreeter.greet(), "Hello, JSProcessorGreeter!"); jsCreatedGreeter.release(); - const swiftCreatedGreeter = swiftCounter.createGreeter(); - assert.equal(swiftCreatedGreeter.name, "CounterGreeter"); - assert.equal(swiftCreatedGreeter.greet(), "Hello, CounterGreeter!"); + const swiftCreatedGreeter = swiftProcessor.createGreeter(); + assert.equal(swiftCreatedGreeter.name, "ProcessorGreeter"); + assert.equal(swiftCreatedGreeter.greet(), "Hello, ProcessorGreeter!"); swiftCreatedGreeter.release(); const optGreeterTest = new exports.Greeter("OptionalTest"); - assert.equal(jsCounter.processOptionalGreeter(optGreeterTest), "JSCounter processed optional: Hello, OptionalTest!"); - assert.equal(jsCounter.processOptionalGreeter(null), "JSCounter received null"); - assert.equal(swiftCounter.processOptionalGreeter(optGreeterTest), "SwiftCounter processed optional: Hello, OptionalTest!"); - assert.equal(swiftCounter.processOptionalGreeter(null), "SwiftCounter received nil"); + assert.equal(jsProcessor.processOptionalGreeter(optGreeterTest), "JSProcessor processed optional: Hello, OptionalTest!"); + assert.equal(jsProcessor.processOptionalGreeter(null), "JSProcessor received null"); + assert.equal(swiftProcessor.processOptionalGreeter(optGreeterTest), "SwiftProcessor processed optional: Hello, OptionalTest!"); + assert.equal(swiftProcessor.processOptionalGreeter(null), "SwiftProcessor received nil"); optGreeterTest.release(); - const jsOptGreeter = jsCounter.createOptionalGreeter(); + const jsOptGreeter = jsProcessor.createOptionalGreeter(); assert.notEqual(jsOptGreeter, null); assert.equal(jsOptGreeter.name, "JSOptionalGreeter"); jsOptGreeter.release(); - const swiftOptGreeter = swiftCounter.createOptionalGreeter(); + const swiftOptGreeter = swiftProcessor.createOptionalGreeter(); assert.notEqual(swiftOptGreeter, null); - assert.equal(swiftOptGreeter.name, "OptionalCounterGreeter"); + assert.equal(swiftOptGreeter.name, "OptionalProcessorGreeter"); swiftOptGreeter.release(); - assert.equal(jsCounter.optionalTag, null); - jsCounter.optionalTag = "test-tag"; - assert.equal(jsCounter.optionalTag, "test-tag"); - jsCounter.optionalTag = null; - assert.equal(jsCounter.optionalTag, null); + assert.equal(jsProcessor.optionalTag, null); + jsProcessor.optionalTag = "test-tag"; + assert.equal(jsProcessor.optionalTag, "test-tag"); + jsProcessor.optionalTag = null; + assert.equal(jsProcessor.optionalTag, null); + + const successResult = { tag: exports.Result.Tag.Success, param0: "Operation completed" }; + const failureResult = { tag: exports.Result.Tag.Failure, param0: 500 }; + + jsProcessor.handleAPIResult(successResult); + assert.deepEqual(jsProcessor.getAPIResult(), successResult); + + jsProcessor.handleAPIResult(failureResult); + assert.deepEqual(jsProcessor.getAPIResult(), failureResult); + + assert.equal(jsProcessor.apiResult, null); + jsProcessor.apiResult = successResult; + assert.deepEqual(jsProcessor.apiResult, successResult); + jsProcessor.apiResult = null; + assert.equal(jsProcessor.apiResult, null); testGreeter.release(); swiftManager.release(); - swiftCounter.release(); + swiftProcessor.release(); - let optionalCounterValue = 100; - let optionalCounterLabel = "optional"; - const optionalCounter = { + let optionalProcessorValue = 100; + let optionalProcessorLabel = "optional"; + const optionalProcessor = { count: 100, - name: "OptionalCounter", + name: "OptionalProcessor", optionalTag: "optional-tag", - increment(amount) { optionalCounterValue += amount; this.count += amount; }, - getValue() { return optionalCounterValue; }, - setLabelElements(labelPrefix, labelSuffix) { optionalCounterLabel = labelPrefix + labelSuffix; }, - getLabel() { return optionalCounterLabel; }, - isEven() { return optionalCounterValue % 2 === 0; }, - processGreeter(greeter) { return `OptionalCounter processed: ${greeter.greet()}`; }, - createGreeter() { return new exports.Greeter("OptionalCounterGreeter"); }, + apiResult: null, + increment(amount) { optionalProcessorValue += amount; this.count += amount; }, + getValue() { return optionalProcessorValue; }, + setLabelElements(labelPrefix, labelSuffix) { optionalProcessorLabel = labelPrefix + labelSuffix; }, + getLabel() { return optionalProcessorLabel; }, + isEven() { return optionalProcessorValue % 2 === 0; }, + processGreeter(greeter) { return `OptionalProcessor processed: ${greeter.greet()}`; }, + createGreeter() { return new exports.Greeter("OptionalProcessorGreeter"); }, processOptionalGreeter(greeter) { - return greeter ? `OptionalCounter processed optional: ${greeter.greet()}` : "OptionalCounter received null"; + return greeter ? `OptionalProcessor processed optional: ${greeter.greet()}` : "OptionalProcessor received null"; }, - createOptionalGreeter() { return null; } + createOptionalGreeter() { return null; }, + handleAPIResult(result) { }, + getAPIResult() { return { tag: exports.APIResult.Tag.Info }; } }; - let mainCounterValue = 0; - let mainCounterLabel = "main"; - const mainCounter = { + let mainProcessorValue = 0; + let mainProcessorLabel = "main"; + const mainProcessor = { count: 0, - name: "MainCounter", + name: "MainProcessor", optionalTag: null, - increment(amount) { mainCounterValue += amount; this.count += amount; }, - getValue() { return mainCounterValue; }, - setLabelElements(labelPrefix, labelSuffix) { mainCounterLabel = labelPrefix + labelSuffix; }, - getLabel() { return mainCounterLabel; }, - isEven() { return mainCounterValue % 2 === 0; }, - processGreeter(greeter) { return `MainCounter processed: ${greeter.greet()}`; }, - createGreeter() { return new exports.Greeter("MainCounterGreeter"); }, + apiResult: null, + increment(amount) { mainProcessorValue += amount; this.count += amount; }, + getValue() { return mainProcessorValue; }, + setLabelElements(labelPrefix, labelSuffix) { mainProcessorLabel = labelPrefix + labelSuffix; }, + getLabel() { return mainProcessorLabel; }, + isEven() { return mainProcessorValue % 2 === 0; }, + processGreeter(greeter) { return `MainProcessor processed: ${greeter.greet()}`; }, + createGreeter() { return new exports.Greeter("MainProcessorGreeter"); }, processOptionalGreeter(greeter) { - return greeter ? `MainCounter processed optional: ${greeter.greet()}` : "MainCounter received null"; + return greeter ? `MainProcessor processed optional: ${greeter.greet()}` : "MainProcessor received null"; }, - createOptionalGreeter() { return new exports.Greeter("MainOptionalGreeter"); } + createOptionalGreeter() { return new exports.Greeter("MainOptionalGreeter"); }, + handleAPIResult(result) { }, + getAPIResult() { return { tag: exports.APIResult.Tag.Info }; } }; - const managerWithOptional = new exports.CounterManager(mainCounter); + const managerWithOptional = new exports.DataProcessorManager(mainProcessor); - assert.equal(managerWithOptional.backupCounter, null); + assert.equal(managerWithOptional.backupProcessor, null); assert.equal(managerWithOptional.hasBackup(), false); assert.equal(managerWithOptional.getBackupValue(), null); - managerWithOptional.backupCounter = optionalCounter; - assert.notEqual(managerWithOptional.backupCounter, null); + managerWithOptional.backupProcessor = optionalProcessor; + assert.notEqual(managerWithOptional.backupProcessor, null); assert.equal(managerWithOptional.hasBackup(), true); managerWithOptional.incrementBoth(); @@ -973,23 +998,23 @@ function testProtocolSupport(exports) { assert.equal(managerWithOptional.getCurrentValue(), 2); assert.equal(managerWithOptional.getBackupValue(), 102); - managerWithOptional.backupCounter = null; - assert.equal(managerWithOptional.backupCounter, null); + managerWithOptional.backupProcessor = null; + assert.equal(managerWithOptional.backupProcessor, null); assert.equal(managerWithOptional.hasBackup(), false); managerWithOptional.incrementBoth(); assert.equal(managerWithOptional.getCurrentValue(), 3); assert.equal(managerWithOptional.getBackupValue(), null); - const swiftBackupCounter = new exports.SwiftCounter(); - swiftBackupCounter.increment(1); - managerWithOptional.backupCounter = swiftBackupCounter; + const swiftBackupProcessor = new exports.SwiftDataProcessor(); + swiftBackupProcessor.increment(1); + managerWithOptional.backupProcessor = swiftBackupProcessor; assert.equal(managerWithOptional.hasBackup(), true); assert.equal(managerWithOptional.getBackupValue(), 1); - assert.equal(swiftBackupCounter.count, 1); - assert.equal(swiftBackupCounter.name, "SwiftCounter"); + assert.equal(swiftBackupProcessor.count, 1); + assert.equal(swiftBackupProcessor.name, "SwiftDataProcessor"); managerWithOptional.release(); - swiftBackupCounter.release(); + swiftBackupProcessor.release(); } From e7e1b79b683b400209876d6ae254afa466ae62df Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Thu, 16 Oct 2025 14:06:22 +0200 Subject: [PATCH 5/6] BridgeJS: Fix for side channelling values on properties getters / setters --- .../Generated/BridgeJS.ExportSwift.swift | 114 +++- .../Sources/BridgeJSCore/ExportSwift.swift | 134 +++-- .../Sources/BridgeJSCore/ImportTS.swift | 24 +- .../Sources/BridgeJSLink/BridgeJSLink.swift | 92 ++++ .../Sources/BridgeJSLink/JSGlueGen.swift | 173 +++--- .../BridgeJSSkeleton/BridgeJSSkeleton.swift | 4 +- .../BridgeJSToolTests/Inputs/Protocol.swift | 23 +- .../ArrayParameter.Import.js | 35 ++ .../BridgeJSLinkTests/Async.Export.js | 35 ++ .../BridgeJSLinkTests/Async.Import.js | 35 ++ .../DefaultParameters.Export.js | 35 ++ .../EnumAssociatedValue.Export.js | 35 ++ .../BridgeJSLinkTests/EnumCase.Export.js | 35 ++ .../BridgeJSLinkTests/EnumNamespace.Export.js | 35 ++ .../BridgeJSLinkTests/EnumRawType.Export.js | 35 ++ .../BridgeJSLinkTests/Interface.Import.js | 35 ++ .../InvalidPropertyNames.Import.js | 35 ++ .../MultipleImportedTypes.Import.js | 35 ++ .../BridgeJSLinkTests/Namespaces.Export.js | 35 ++ .../BridgeJSLinkTests/Optionals.Export.js | 35 ++ .../PrimitiveParameters.Export.js | 35 ++ .../PrimitiveParameters.Import.js | 35 ++ .../PrimitiveReturn.Export.js | 35 ++ .../PrimitiveReturn.Import.js | 35 ++ .../BridgeJSLinkTests/PropertyTypes.Export.js | 35 ++ .../BridgeJSLinkTests/Protocol.Export.d.ts | 31 +- .../BridgeJSLinkTests/Protocol.Export.js | 181 ++++++- .../StaticFunctions.Export.js | 35 ++ .../StaticProperties.Export.js | 35 ++ .../StringParameter.Export.js | 35 ++ .../StringParameter.Import.js | 35 ++ .../BridgeJSLinkTests/StringReturn.Export.js | 35 ++ .../BridgeJSLinkTests/StringReturn.Import.js | 35 ++ .../BridgeJSLinkTests/SwiftClass.Export.js | 35 ++ .../TS2SkeletonLike.Import.js | 35 ++ .../BridgeJSLinkTests/Throws.Export.js | 35 ++ .../BridgeJSLinkTests/TypeAlias.Import.js | 35 ++ .../TypeScriptClass.Import.js | 35 ++ .../VoidParameterVoidReturn.Export.js | 35 ++ .../VoidParameterVoidReturn.Import.js | 35 ++ .../ExportSwiftTests/DefaultParameters.swift | 4 +- .../EnumAssociatedValue.swift | 25 +- .../ExportSwiftTests/EnumCase.swift | 16 +- .../ExportSwiftTests/EnumNamespace.swift | 8 +- .../ExportSwiftTests/Protocol.json | 143 ++++- .../ExportSwiftTests/Protocol.swift | 175 ++++++- .../ExportSwiftTests/StaticFunctions.swift | 9 +- .../ExportSwiftTests/StaticProperties.swift | 4 +- .../JavaScriptKit/BridgeJSInstrincics.swift | 461 ++++++++++------ .../Exporting-Swift-Protocols.md | 5 +- .../BridgeJSRuntimeTests/ExportAPITests.swift | 70 ++- .../Generated/BridgeJS.ExportSwift.swift | 408 +++++++++++++-- .../JavaScript/BridgeJS.ExportSwift.json | 494 +++++++++++++++++- Tests/prelude.mjs | 319 ++++++----- 54 files changed, 3417 insertions(+), 585 deletions(-) diff --git a/Benchmarks/Sources/Generated/BridgeJS.ExportSwift.swift b/Benchmarks/Sources/Generated/BridgeJS.ExportSwift.swift index d02d0fae..ab0cbb19 100644 --- a/Benchmarks/Sources/Generated/BridgeJS.ExportSwift.swift +++ b/Benchmarks/Sources/Generated/BridgeJS.ExportSwift.swift @@ -7,7 +7,7 @@ @_spi(BridgeJS) import JavaScriptKit extension APIResult: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIResult { + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> APIResult { switch caseId { case 0: return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -26,6 +26,43 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .failure(let param0): + _swift_js_push_int(Int32(param0)) + return Int32(1) + case .flag(let param0): + _swift_js_push_int(param0 ? 1 : 0) + return Int32(2) + case .rate(let param0): + _swift_js_push_f32(param0) + return Int32(3) + case .precise(let param0): + _swift_js_push_f64(param0) + return Int32(4) + case .info: + return Int32(5) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> APIResult { + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> APIResult { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): @@ -53,7 +90,7 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } extension ComplexResult: _BridgedSwiftAssociatedValueEnum { - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> ComplexResult { + private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> ComplexResult { switch caseId { case 0: return .success(String.bridgeJSLiftParameter(_swift_js_pop_param_int32(), _swift_js_pop_param_int32())) @@ -74,6 +111,79 @@ extension ComplexResult: _BridgedSwiftAssociatedValueEnum { } } + // MARK: Protocol Export + + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + switch self { + case .success(let param0): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(0) + case .error(let param0, let param1): + var __bjs_param0 = param0 + __bjs_param0.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + _swift_js_push_int(Int32(param1)) + return Int32(1) + case .location(let param0, let param1, let param2): + _swift_js_push_f64(param0) + _swift_js_push_f64(param1) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(2) + case .status(let param0, let param1, let param2): + _swift_js_push_int(param0 ? 1 : 0) + _swift_js_push_int(Int32(param1)) + var __bjs_param2 = param2 + __bjs_param2.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(3) + case .coordinates(let param0, let param1, let param2): + _swift_js_push_f64(param0) + _swift_js_push_f64(param1) + _swift_js_push_f64(param2) + return Int32(4) + case .comprehensive(let param0, let param1, let param2, let param3, let param4, let param5, let param6, let param7, let param8): + _swift_js_push_int(param0 ? 1 : 0) + _swift_js_push_int(param1 ? 1 : 0) + _swift_js_push_int(Int32(param2)) + _swift_js_push_int(Int32(param3)) + _swift_js_push_f64(param4) + _swift_js_push_f64(param5) + var __bjs_param6 = param6 + __bjs_param6.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + var __bjs_param7 = param7 + __bjs_param7.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + var __bjs_param8 = param8 + __bjs_param8.withUTF8 { ptr in + _swift_js_push_string(ptr.baseAddress, Int32(ptr.count)) + } + return Int32(5) + case .info: + return Int32(6) + } + } + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> ComplexResult { + return _bridgeJSLiftFromCaseId(caseId) + } + + // MARK: ExportSwift + + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ caseId: Int32) -> ComplexResult { + return _bridgeJSLiftFromCaseId(caseId) + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() { switch self { case .success(let param0): diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift index 7aa4503f..4cdc8a3b 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ExportSwift.swift @@ -588,7 +588,6 @@ public class ExportSwift { baseName: name, namespace: finalNamespace, staticContext: isStatic ? staticContext : nil, - operation: nil, className: classNameForABI ) @@ -1054,8 +1053,6 @@ public class ExportSwift { let abiName = ABINameGenerator.generateABIName( baseName: name, namespace: namespace, - staticContext: nil, - operation: nil, className: protocolName ) @@ -1167,6 +1164,8 @@ public class ExportSwift { } else { var numericExpr = element.rawValue?.value var isNegative = false + + // Check for prefix operator (for negative numbers) if let prefixExpr = numericExpr?.as(PrefixOperatorExprSyntax.self), prefixExpr.operator.text == "-" { @@ -1790,8 +1789,7 @@ public class ExportSwift { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> \(raw: typeName) { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> \(raw: typeName) { return _bridgeJSLiftFromCaseId(caseId) } @@ -1868,8 +1866,6 @@ public class ExportSwift { return cases } - /// Generates code to push associated value payloads to side channels - /// This helper is reused by both lowerParameter and lowerReturn to avoid duplication private func generatePayloadPushingCode( associatedValues: [AssociatedValue] ) -> [String] { @@ -2229,10 +2225,8 @@ public class ExportSwift { """ } - /// Generates an AnyProtocol wrapper struct for a protocol - /// /// Creates a struct that wraps a JSObject and implements protocol methods - /// by calling `@_extern(wasm)` functions that forward to JavaScript + /// by calling `@_extern(wasm)` functions that forward to JavaScript via JSObject ID func renderProtocolWrapper(protocol proto: ExportedProtocol) throws -> DeclSyntax { let wrapperName = "Any\(proto.name)" let protocolName = proto.name @@ -2253,57 +2247,73 @@ public class ExportSwift { var externParams: [String] = ["this: Int32"] for param in method.parameters { let loweringInfo = try param.type.loweringParameterInfo(context: .protocolExport) - assert( - loweringInfo.loweredParameters.count == 1, - "Protocol parameters must lower to a single WASM type" - ) - let (_, wasmType) = loweringInfo.loweredParameters[0] - externParams.append("\(param.name): \(wasmType.swiftType)") + for (paramName, wasmType) in loweringInfo.loweredParameters { + let fullParamName = + loweringInfo.loweredParameters.count > 1 + ? "\(param.name)\(paramName.capitalizedFirstLetter)" : param.name + externParams.append("\(fullParamName): \(wasmType.swiftType)") + } } + var preCallStatements: [String] = [] var callArgs: [String] = ["this: Int32(bitPattern: jsObject.id)"] for param in method.parameters { - callArgs.append("\(param.name): \(param.name).bridgeJSLowerParameter()") + let loweringInfo = try param.type.loweringParameterInfo(context: .protocolExport) + if case .optional = param.type, loweringInfo.loweredParameters.count > 1 { + let isSomeName = "\(param.name)\(loweringInfo.loweredParameters[0].name.capitalizedFirstLetter)" + let wrappedName = "\(param.name)\(loweringInfo.loweredParameters[1].name.capitalizedFirstLetter)" + preCallStatements.append( + "let (\(isSomeName), \(wrappedName)) = \(param.name).bridgeJSLowerParameterWithPresence()" + ) + callArgs.append("\(isSomeName): \(isSomeName)") + callArgs.append("\(wrappedName): \(wrappedName)") + } else { + callArgs.append("\(param.name): \(param.name).bridgeJSLowerParameter()") + } } let returnTypeStr: String let externReturnType: String let callCode: DeclSyntax + let preCallCode = preCallStatements.isEmpty ? "" : preCallStatements.joined(separator: "\n") + "\n" + if method.returnType == .void { returnTypeStr = "" externReturnType = "" callCode = """ - _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) + \(raw: preCallCode)_extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) """ } else { returnTypeStr = " -> \(method.returnType.swiftType)" - let liftingInfo = try method.returnType.liftingReturnInfo(context: .protocolExport) + let liftingInfo = try method.returnType.liftingReturnInfo( + context: .protocolExport + ) if case .optional = method.returnType { if let abiType = liftingInfo.valueToLift { externReturnType = " -> \(abiType.swiftType)" callCode = """ - let ret = _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) + \(raw: preCallCode)let ret = _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) return \(raw: method.returnType.swiftType).bridgeJSLiftReturn(ret) """ } else { externReturnType = "" callCode = """ - _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) + \(raw: preCallCode)_extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) return \(raw: method.returnType.swiftType).bridgeJSLiftReturn() """ } } else if let abiType = liftingInfo.valueToLift { externReturnType = " -> \(abiType.swiftType)" callCode = """ - let ret = _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) + \(raw: preCallCode)let ret = _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) return \(raw: method.returnType.swiftType).bridgeJSLiftReturn(ret) """ } else { externReturnType = "" callCode = """ - _extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) + \(raw: preCallCode)_extern_\(raw: method.name)(\(raw: callArgs.joined(separator: ", "))) return \(raw: method.returnType.swiftType).bridgeJSLiftReturn() """ } @@ -2352,73 +2362,106 @@ public class ExportSwift { ) throws -> DeclSyntax { let getterAbiName = ABINameGenerator.generateABIName( baseName: property.name, - namespace: nil, - staticContext: nil, operation: "get", className: protocolName ) let setterAbiName = ABINameGenerator.generateABIName( baseName: property.name, - namespace: nil, - staticContext: nil, operation: "set", className: protocolName ) - // Generate getter + let usesSideChannel: Bool + if case .optional(let wrappedType) = property.type { + switch wrappedType { + case .string: + usesSideChannel = true + case .rawValueEnum(_, let rawType): + switch rawType { + case .string: + usesSideChannel = true + default: + usesSideChannel = true + } + case .int, .float, .double: + usesSideChannel = true + case .bool, .caseEnum, .associatedValueEnum, .swiftHeapObject: + usesSideChannel = false + default: + usesSideChannel = false + } + } else { + usesSideChannel = false + } + let liftingInfo = try property.type.liftingReturnInfo(context: .protocolExport) let getterReturnType: String - let getterCallCode: String + let getterBody: String - if let abiType = liftingInfo.valueToLift { + if usesSideChannel { + // Optional case/raw enums use side-channel reading (Void return) + getterReturnType = "" + getterBody = """ + _extern_get(this: Int32(bitPattern: jsObject.id)) + return \(property.type.swiftType).bridgeJSLiftReturnFromSideChannel() + """ + } else if let abiType = liftingInfo.valueToLift { getterReturnType = " -> \(abiType.swiftType)" - getterCallCode = """ + getterBody = """ let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) return \(property.type.swiftType).bridgeJSLiftReturn(ret) """ } else { - // For String and other types that use tmpRetString getterReturnType = "" - getterCallCode = """ + getterBody = """ _extern_get(this: Int32(bitPattern: jsObject.id)) return \(property.type.swiftType).bridgeJSLiftReturn() """ } if property.isReadonly { - // Readonly property - only getter return """ var \(raw: property.name): \(raw: property.type.swiftType) { get { @_extern(wasm, module: "\(raw: moduleName)", name: "\(raw: getterAbiName)") func _extern_get(this: Int32)\(raw: getterReturnType) - \(raw: getterCallCode) + \(raw: getterBody) } } """ } else { - // Readwrite property - getter and setter let loweringInfo = try property.type.loweringParameterInfo(context: .protocolExport) - assert( - loweringInfo.loweredParameters.count == 1, - "Protocol property setters must lower to a single WASM parameter" - ) - let (paramName, wasmType) = loweringInfo.loweredParameters[0] - let setterParams = "this: Int32, \(paramName): \(wasmType.swiftType)" - let setterCallArgs = "this: Int32(bitPattern: jsObject.id), \(paramName): newValue.bridgeJSLowerParameter()" + let setterParams = + (["this: Int32"] + loweringInfo.loweredParameters.map { "\($0.name): \($0.type.swiftType)" }).joined( + separator: ", " + ) + + let setterBody: String + if case .optional = property.type, loweringInfo.loweredParameters.count > 1 { + let isSomeParam = loweringInfo.loweredParameters[0].name + let wrappedParam = loweringInfo.loweredParameters[1].name + setterBody = """ + let (\(isSomeParam), \(wrappedParam)) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), \(isSomeParam): \(isSomeParam), \(wrappedParam): \(wrappedParam)) + """ + } else { + let paramName = loweringInfo.loweredParameters[0].name + setterBody = + "_extern_set(this: Int32(bitPattern: jsObject.id), \(paramName): newValue.bridgeJSLowerParameter())" + } return """ var \(raw: property.name): \(raw: property.type.swiftType) { get { @_extern(wasm, module: "\(raw: moduleName)", name: "\(raw: getterAbiName)") func _extern_get(this: Int32)\(raw: getterReturnType) - \(raw: getterCallCode) + \(raw: getterBody) } set { @_extern(wasm, module: "\(raw: moduleName)", name: "\(raw: setterAbiName)") func _extern_set(\(raw: setterParams)) - _extern_set(\(raw: setterCallArgs)) + \(raw: setterBody) } } """ @@ -2600,7 +2643,6 @@ extension BridgeType { throw BridgeJSCoreError("Namespace enums are not supported to pass as parameters") } } - } extension DeclModifierSyntax { diff --git a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift index 26e22e87..4589817d 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSCore/ImportTS.swift @@ -459,8 +459,8 @@ extension BridgeType { case .importTS: throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") case .protocolExport: - let wasmType = rawType == .string ? WasmCoreType.i32 : (rawType.wasmCoreType ?? .i32) - return LoweringParameterInfo(loweredParameters: [("value", wasmType)]) + // For protocol export we return .i32 for String raw value type instead of nil + return LoweringParameterInfo(loweredParameters: [("value", rawType.wasmCoreType ?? .i32)]) } case .associatedValueEnum: switch context { @@ -477,11 +477,9 @@ extension BridgeType { throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") case .protocolExport: let wrappedInfo = try wrappedType.loweringParameterInfo(context: context) - guard wrappedInfo.loweredParameters.count == 1 else { - throw BridgeJSCoreError("Optional wrapped type must lower to single parameter") - } - let (_, wrappedWasmType) = wrappedInfo.loweredParameters[0] - return LoweringParameterInfo(loweredParameters: [("value", wrappedWasmType)]) + var params = [("isSome", WasmCoreType.i32)] + params.append(contentsOf: wrappedInfo.loweredParameters) + return LoweringParameterInfo(loweredParameters: params) } } } @@ -498,7 +496,9 @@ extension BridgeType { static let void = LiftingReturnInfo(valueToLift: nil) } - func liftingReturnInfo(context: BridgeContext = .importTS) throws -> LiftingReturnInfo { + func liftingReturnInfo( + context: BridgeContext = .importTS + ) throws -> LiftingReturnInfo { switch self { case .bool: return .bool case .int: return .int @@ -533,15 +533,15 @@ extension BridgeType { case .importTS: throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") case .protocolExport: - let wasmType = rawType == .string ? WasmCoreType.i32 : (rawType.wasmCoreType ?? .i32) - return LiftingReturnInfo(valueToLift: wasmType) + // For protocol export we return .i32 for String raw value type instead of nil + return LiftingReturnInfo(valueToLift: rawType.wasmCoreType ?? .i32) } case .associatedValueEnum: switch context { case .importTS: throw BridgeJSCoreError("Enum types are not yet supported in TypeScript imports") case .protocolExport: - return LiftingReturnInfo(valueToLift: nil) + return LiftingReturnInfo(valueToLift: .i32) } case .namespaceEnum: throw BridgeJSCoreError("Namespace enums cannot be used as return values") @@ -551,7 +551,7 @@ extension BridgeType { throw BridgeJSCoreError("Optional types are not yet supported in TypeScript imports") case .protocolExport: let wrappedInfo = try wrappedType.liftingReturnInfo(context: context) - return wrappedInfo + return LiftingReturnInfo(valueToLift: wrappedInfo.valueToLift) } } } diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index 4445ddeb..6abfd305 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -589,6 +589,61 @@ struct BridgeJSLink { printer.write("}") } printer.write("}") + printer.write("bjs[\"swift_js_get_optional_int_presence\"] = function() {") + printer.indent { + printer.write("return \(JSGlueVariableScope.reservedStorageToReturnOptionalInt) != null ? 1 : 0;") + } + printer.write("}") + printer.write("bjs[\"swift_js_get_optional_int_value\"] = function() {") + printer.indent { + printer.write("const value = \(JSGlueVariableScope.reservedStorageToReturnOptionalInt);") + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = undefined;") + printer.write("return value;") + } + printer.write("}") + printer.write("bjs[\"swift_js_get_optional_string\"] = function() {") + printer.indent { + printer.write("const str = \(JSGlueVariableScope.reservedStorageToReturnString);") + printer.write("\(JSGlueVariableScope.reservedStorageToReturnString) = undefined;") + printer.write("if (str == null) {") + printer.indent { + printer.write("return -1;") + } + printer.write("} else {") + printer.indent { + printer.write("const bytes = \(JSGlueVariableScope.reservedTextEncoder).encode(str);") + printer.write("\(JSGlueVariableScope.reservedStorageToReturnBytes) = bytes;") + printer.write("return bytes.length;") + } + printer.write("}") + } + printer.write("}") + printer.write("bjs[\"swift_js_get_optional_float_presence\"] = function() {") + printer.indent { + printer.write("return \(JSGlueVariableScope.reservedStorageToReturnOptionalFloat) != null ? 1 : 0;") + } + printer.write("}") + printer.write("bjs[\"swift_js_get_optional_float_value\"] = function() {") + printer.indent { + printer.write("const value = \(JSGlueVariableScope.reservedStorageToReturnOptionalFloat);") + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalFloat) = undefined;") + printer.write("return value;") + } + printer.write("}") + printer.write("bjs[\"swift_js_get_optional_double_presence\"] = function() {") + printer.indent { + printer.write( + "return \(JSGlueVariableScope.reservedStorageToReturnOptionalDouble) != null ? 1 : 0;" + ) + } + printer.write("}") + printer.write("bjs[\"swift_js_get_optional_double_value\"] = function() {") + printer.indent { + printer.write("const value = \(JSGlueVariableScope.reservedStorageToReturnOptionalDouble);") + printer.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalDouble) = undefined;") + printer.write("return value;") + } + printer.write("}") } } return printer @@ -1962,6 +2017,43 @@ extension BridgeJSLink { } func callPropertyGetter(name: String, returnType: BridgeType) throws -> String? { + if context == .protocolExport, case .optional(let wrappedType) = returnType { + let usesSideChannel: Bool + switch wrappedType { + case .string, .int, .float, .double, .jsObject, .swiftProtocol: + usesSideChannel = true + case .rawValueEnum: + usesSideChannel = true + case .bool, .caseEnum, .swiftHeapObject, .associatedValueEnum: + usesSideChannel = false + default: + usesSideChannel = false + } + + if usesSideChannel { + let resultVar = scope.variable("ret") + body.write( + "let \(resultVar) = \(JSGlueVariableScope.reservedSwift).memory.getObject(self).\(name);" + ) + + switch wrappedType { + case .string, .rawValueEnum(_, .string): + body.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(resultVar);") + case .int, .rawValueEnum(_, .int): + body.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalInt) = \(resultVar);") + case .float, .rawValueEnum(_, .float): + body.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalFloat) = \(resultVar);") + case .double, .rawValueEnum(_, .double): + body.write("\(JSGlueVariableScope.reservedStorageToReturnOptionalDouble) = \(resultVar);") + case .jsObject, .swiftProtocol: + body.write("\(JSGlueVariableScope.reservedStorageToReturnString) = \(resultVar);") + default: + break + } + return nil // Side-channel types return nil (no direct return value) + } + } + return try call( callExpr: "\(JSGlueVariableScope.reservedSwift).memory.getObject(self).\(name)", returnType: returnType diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 45397471..9cdf9d72 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -263,21 +263,19 @@ struct IntrinsicJSFragment: Sendable { ) } - static func optionalLiftParameter(wrappedType: BridgeType, context: BridgeContext) throws -> IntrinsicJSFragment { + static func optionalLiftParameter(wrappedType: BridgeType) throws -> IntrinsicJSFragment { return IntrinsicJSFragment( parameters: ["isSome", "wrappedValue"], printCode: { arguments, scope, printer, cleanupCode in let isSome = arguments[0] let wrappedValue = arguments[1] - let resultExpr: String + switch wrappedType { case .int, .float, .double, .caseEnum: resultExpr = "\(isSome) ? \(wrappedValue) : null" - case .bool: resultExpr = "\(isSome) ? \(wrappedValue) !== 0 : null" - case .string: let objectLabel = scope.variable("obj") printer.write("let \(objectLabel);") @@ -290,14 +288,11 @@ struct IntrinsicJSFragment: Sendable { } printer.write("}") resultExpr = "\(isSome) ? \(objectLabel) : null" - case .swiftHeapObject(let name): resultExpr = "\(isSome) ? \(name).__construct(\(wrappedValue)) : null" - case .jsObject: resultExpr = "\(isSome) ? \(JSGlueVariableScope.reservedSwift).memory.getObject(\(wrappedValue)) : null" - case .rawValueEnum(_, let rawType): switch rawType { case .string: @@ -317,7 +312,18 @@ struct IntrinsicJSFragment: Sendable { default: resultExpr = "\(isSome) ? \(wrappedValue) : null" } - + case .associatedValueEnum(let fullName): + let base = fullName.components(separatedBy: ".").last ?? fullName + let enumVar = scope.variable("enumValue") + printer.write("let \(enumVar);") + printer.write("if (\(isSome)) {") + printer.indent { + printer.write( + "\(enumVar) = enumHelpers.\(base).raise(\(wrappedValue), \(JSGlueVariableScope.reservedTmpRetStrings), \(JSGlueVariableScope.reservedTmpRetInts), \(JSGlueVariableScope.reservedTmpRetF32s), \(JSGlueVariableScope.reservedTmpRetF64s));" + ) + } + printer.write("}") + resultExpr = "\(isSome) ? \(enumVar) : null" default: resultExpr = "\(isSome) ? \(wrappedValue) : null" } @@ -371,6 +377,9 @@ struct IntrinsicJSFragment: Sendable { cleanupCode.write("if (\(cleanupVar)) { \(cleanupVar)(); }") return ["+\(isSomeVar)", "\(isSomeVar) ? \(caseIdVar) : 0"] + case .rawValueEnum: + // Raw value enums with optional - falls through to handle based on raw type + return ["+\(isSomeVar)", "\(isSomeVar) ? \(value) : 0"] default: switch wrappedType { case .swiftHeapObject: @@ -489,11 +498,9 @@ struct IntrinsicJSFragment: Sendable { static func optionalLowerReturn(wrappedType: BridgeType) throws -> IntrinsicJSFragment { switch wrappedType { - case .bool, .int, .float, .double, .string, .swiftHeapObject, .jsObject, .swiftProtocol, .caseEnum, - .rawValueEnum, .associatedValueEnum: - break case .void, .optional, .namespaceEnum: throw BridgeJSLinkError(message: "Unsupported optional wrapped type for protocol export: \(wrappedType)") + default: break } return IntrinsicJSFragment( @@ -501,7 +508,6 @@ struct IntrinsicJSFragment: Sendable { printCode: { arguments, scope, printer, cleanupCode in let value = arguments[0] let isSomeVar = scope.variable("isSome") - printer.write("const \(isSomeVar) = \(value) != null;") switch wrappedType { @@ -509,10 +515,12 @@ struct IntrinsicJSFragment: Sendable { printer.write( "bjs[\"swift_js_return_optional_bool\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) ? 1 : 0) : 0);" ) - case .int, .caseEnum: + case .int: printer.write( "bjs[\"swift_js_return_optional_int\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) | 0) : 0);" ) + case .caseEnum: + printer.write("return \(isSomeVar) ? (\(value) | 0) : -1;") case .float: printer.write( "bjs[\"swift_js_return_optional_float\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? Math.fround(\(value)) : 0.0);" @@ -537,9 +545,6 @@ struct IntrinsicJSFragment: Sendable { printer.write("return -1;") } printer.write("}") - - case .swiftHeapObject: - printer.write("return \(isSomeVar) ? \(value).pointer : 0;") case .jsObject, .swiftProtocol: let idVar = scope.variable("id") printer.write("let \(idVar) = 0;") @@ -561,30 +566,31 @@ struct IntrinsicJSFragment: Sendable { printer.write( "bjs[\"swift_js_return_optional_string\"](1, \(bytesVar), \(bytesVar).length);" ) - printer.write("return \(bytesVar).length;") } printer.write("} else {") printer.indent { printer.write("bjs[\"swift_js_return_optional_string\"](0, 0, 0);") - printer.write("return -1;") } printer.write("}") - case .bool: - printer.write( - "bjs[\"swift_js_return_optional_bool\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) ? 1 : 0) : 0);" - ) - case .float: - printer.write( - "bjs[\"swift_js_return_optional_float\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? Math.fround(\(value)) : 0.0);" - ) - case .double: - printer.write( - "bjs[\"swift_js_return_optional_double\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? \(value) : 0.0);" - ) default: - printer.write( - "bjs[\"swift_js_return_optional_int\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) | 0) : 0);" - ) + switch rawType { + case .bool: + printer.write( + "bjs[\"swift_js_return_optional_bool\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) ? 1 : 0) : 0);" + ) + case .float: + printer.write( + "bjs[\"swift_js_return_optional_float\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? Math.fround(\(value)) : 0.0);" + ) + case .double: + printer.write( + "bjs[\"swift_js_return_optional_double\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? \(value) : 0.0);" + ) + default: + printer.write( + "bjs[\"swift_js_return_optional_int\"](\(isSomeVar) ? 1 : 0, \(isSomeVar) ? (\(value) | 0) : 0);" + ) + } } case .associatedValueEnum(let fullName): let base = fullName.components(separatedBy: ".").last ?? fullName @@ -595,14 +601,14 @@ struct IntrinsicJSFragment: Sendable { printer.write( "const { caseId: \(caseIdVar), cleanup: \(cleanupVar) } = enumHelpers.\(base).lower(\(value));" ) - cleanupCode.write("if (\(cleanupVar)) { \(cleanupVar)(); }") - printer.write("bjs[\"swift_js_return_optional_int\"](1, \(caseIdVar));") + printer.write("return \(caseIdVar);") } printer.write("} else {") printer.indent { - printer.write("bjs[\"swift_js_return_optional_int\"](0, 0);") + printer.write("return -1;") } printer.write("}") + cleanupCode.write("if (\(cleanupVar)) { \(cleanupVar)(); }") default: () } @@ -671,10 +677,6 @@ struct IntrinsicJSFragment: Sendable { // MARK: - ImportedJS /// Returns a fragment that lifts Wasm core values to JS values for parameters - /// - /// - Parameters: - /// - type: The bridge type to lift - /// - context: The bridge context (defaults to .importTS for backward compatibility) static func liftParameter(type: BridgeType, context: BridgeContext = .importTS) throws -> IntrinsicJSFragment { switch type { case .int, .float, .double: return .identity @@ -682,12 +684,14 @@ struct IntrinsicJSFragment: Sendable { case .string: return .stringLiftParameter case .jsObject: return .jsObjectLiftParameter case .swiftHeapObject(let name): - guard context == .protocolExport else { + switch context { + case .importTS: throw BridgeJSLinkError( message: "swiftHeapObject '\(name)' can only be used in protocol exports, not in \(context)" ) + case .protocolExport: + return .swiftHeapObjectLiftParameter(name) } - return .swiftHeapObjectLiftParameter(name) case .swiftProtocol: return .jsObjectLiftParameter case .void: throw BridgeJSLinkError( @@ -700,8 +704,7 @@ struct IntrinsicJSFragment: Sendable { message: "Optional types are not supported for imported JS functions: \(wrappedType)" ) case .protocolExport: - // Protocol exports support Optional - use existing optionalLiftParameter fragment - return try .optionalLiftParameter(wrappedType: wrappedType, context: context) + return try .optionalLiftParameter(wrappedType: wrappedType) } case .caseEnum: return .identity case .rawValueEnum(_, let rawType): @@ -740,10 +743,6 @@ struct IntrinsicJSFragment: Sendable { } /// Returns a fragment that lowers a JS value to Wasm core values for return values - /// - /// - Parameters: - /// - type: The bridge type to lower - /// - context: The bridge context (defaults to .importTS for backward compatibility) static func lowerReturn(type: BridgeType, context: BridgeContext = .importTS) throws -> IntrinsicJSFragment { switch type { case .int, .float, .double: return .identity @@ -751,12 +750,14 @@ struct IntrinsicJSFragment: Sendable { case .string: return .stringLowerReturn case .jsObject: return .jsObjectLowerReturn case .swiftHeapObject(let name): - guard context == .protocolExport else { + switch context { + case .importTS: throw BridgeJSLinkError( message: "swiftHeapObject '\(name)' can only be used in protocol exports, not in \(context)" ) + case .protocolExport: + return .swiftHeapObjectLowerReturn } - return .swiftHeapObjectLowerReturn case .swiftProtocol: return .jsObjectLowerReturn case .void: return .void case .optional(let wrappedType): @@ -784,21 +785,7 @@ struct IntrinsicJSFragment: Sendable { "Associated value enums are not supported to be returned from imported JS functions: \(fullName)" ) case .protocolExport: - let base = fullName.components(separatedBy: ".").last ?? fullName - return IntrinsicJSFragment( - parameters: ["value"], - printCode: { arguments, scope, printer, cleanupCode in - let value = arguments[0] - let caseIdVar = scope.variable("caseId") - let cleanupVar = scope.variable("cleanup") - printer.write( - "const { caseId: \(caseIdVar), cleanup: \(cleanupVar) } = enumHelpers.\(base).lower(\(value));" - ) - cleanupCode.write("if (\(cleanupVar)) { \(cleanupVar)(); }") - printer.write("return \(caseIdVar);") - return [] - } - ) + return associatedValueLowerReturn(fullName: fullName) } case .namespaceEnum(let string): throw BridgeJSLinkError( @@ -809,6 +796,23 @@ struct IntrinsicJSFragment: Sendable { // MARK: - Enums Payload Fragments + static func associatedValueLowerReturn(fullName: String) -> IntrinsicJSFragment { + let base = fullName.components(separatedBy: ".").last ?? fullName + return IntrinsicJSFragment( + parameters: ["value"], + printCode: { arguments, scope, printer, cleanupCode in + let value = arguments[0] + let caseIdVar = scope.variable("caseId") + let cleanupVar = scope.variable("cleanup") + printer.write( + "const { caseId: \(caseIdVar), cleanup: \(cleanupVar) } = enumHelpers.\(base).lower(\(value));" + ) + cleanupCode.write("if (\(cleanupVar)) { \(cleanupVar)(); }") + printer.write("return \(caseIdVar);") + return [] + } + ) + } /// Fragment for generating an entire associated value enum helper static func associatedValueEnumHelper(enumDefinition: ExportedEnum) -> IntrinsicJSFragment { return IntrinsicJSFragment( @@ -1118,26 +1122,27 @@ struct IntrinsicJSFragment: Sendable { cleanup.write("\(JSGlueVariableScope.reservedSwift).memory.release(\(idVar));") } cleanup.write("}") + case .int: + printer.write( + "\(JSGlueVariableScope.reservedTmpParamInts).push(\(isSomeVar) ? (\(value) | 0) : 0);" + ) + printer.write("\(JSGlueVariableScope.reservedTmpParamInts).push(\(isSomeVar) ? 1 : 0);") + case .bool: + printer.write( + "\(JSGlueVariableScope.reservedTmpParamInts).push(\(isSomeVar) ? (\(value) ? 1 : 0) : 0);" + ) + printer.write("\(JSGlueVariableScope.reservedTmpParamInts).push(\(isSomeVar) ? 1 : 0);") + case .float: + printer.write( + "\(JSGlueVariableScope.reservedTmpParamF32s).push(\(isSomeVar) ? Math.fround(\(value)) : 0.0);" + ) + printer.write("\(JSGlueVariableScope.reservedTmpParamInts).push(\(isSomeVar) ? 1 : 0);") + case .double: + printer.write( + "\(JSGlueVariableScope.reservedTmpParamF64s).push(\(isSomeVar) ? \(value) : 0.0);" + ) + printer.write("\(JSGlueVariableScope.reservedTmpParamInts).push(\(isSomeVar) ? 1 : 0);") default: - switch wrappedType { - case .int: - printer.write( - "\(JSGlueVariableScope.reservedTmpParamInts).push(\(isSomeVar) ? (\(value) | 0) : 0);" - ) - case .bool: - printer.write( - "\(JSGlueVariableScope.reservedTmpParamInts).push(\(isSomeVar) ? (\(value) ? 1 : 0) : 0);" - ) - case .float: - printer.write( - "\(JSGlueVariableScope.reservedTmpParamF32s).push(\(isSomeVar) ? Math.fround(\(value)) : 0.0);" - ) - case .double: - printer.write( - "\(JSGlueVariableScope.reservedTmpParamF64s).push(\(isSomeVar) ? \(value) : 0.0);" - ) - default: () - } printer.write("\(JSGlueVariableScope.reservedTmpParamInts).push(\(isSomeVar) ? 1 : 0);") } diff --git a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift index 233e7903..c9a60275 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSSkeleton/BridgeJSSkeleton.swift @@ -9,8 +9,8 @@ public struct ABINameGenerator { /// Generates ABI name using standardized namespace + context pattern public static func generateABIName( baseName: String, - namespace: [String]?, - staticContext: StaticContext?, + namespace: [String]? = nil, + staticContext: StaticContext? = nil, operation: String? = nil, className: String? = nil ) -> String { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift index 9f2556e9..689f4a35 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/Inputs/Protocol.swift @@ -1,5 +1,12 @@ import JavaScriptKit +@JS enum Direction { + case north + case south + case east + case west +} + @JS enum ExampleEnum: String { case test = "test" case test2 = "test2" @@ -10,6 +17,12 @@ import JavaScriptKit case failure(Int) } +@JS enum Priority: Int { + case low = -1 + case medium = 0 + case high = 1 +} + @JS class Helper { @JS var value: Int @@ -26,8 +39,14 @@ import JavaScriptKit var eventCount: Int { get set } var delegateName: String { get } var optionalName: String? { get set } - var myEnum: ExampleEnum { get set } - var result: Result? { get set } + var optionalRawEnum: ExampleEnum? { get set } + var rawStringEnum: ExampleEnum { get set } + var result: Result { get set } + var optionalResult: Result? { get set } + var direction: Direction { get set } + var directionOptional: Direction? { get set } + var priority: Priority { get set } + var priorityOptional: Priority? { get set } func onSomethingHappened() func onValueChanged(_ value: String) func onCountUpdated(count: Int) -> Bool diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js index 7295699a..c9485c39 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayParameter.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkArray"] = function bjs_checkArray(a) { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js index 92f10f94..a763e45f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Export.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } }, setInstance: (i) => { instance = i; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js index 74fb30c5..b5537ddc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_asyncReturnVoid"] = function bjs_asyncReturnVoid() { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.Export.js index dac7bdfc..a2b07002 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.Export.js @@ -144,6 +144,41 @@ export async function createInstantiator(options, swift) { 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; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js index ea0aef15..b6518d71 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.Export.js @@ -622,6 +622,41 @@ export async function createInstantiator(options, swift) { 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; + } }, setInstance: (i) => { instance = i; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js index 9cbed9a2..04eda063 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.Export.js @@ -162,6 +162,41 @@ export async function createInstantiator(options, swift) { 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; + } }, setInstance: (i) => { instance = i; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js index b934456f..9e645a67 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Export.js @@ -182,6 +182,41 @@ export async function createInstantiator(options, swift) { 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; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js index 6b56108a..15b03a4b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.Export.js @@ -213,6 +213,41 @@ export async function createInstantiator(options, swift) { 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; + } }, setInstance: (i) => { instance = i; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js index cead874b..51921ddc 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Interface.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_returnAnimatable"] = function bjs_returnAnimatable() { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.Import.js index f469072f..b6694c06 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_createArrayBuffer"] = function bjs_createArrayBuffer() { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js index 116933d7..3253d17d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MultipleImportedTypes.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_createDatabaseConnection"] = function bjs_createDatabaseConnection(config) { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js index 5044b4b1..89dd9023 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Export.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.Export.js index f67a06e8..319556b9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.Export.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js index eea05ba1..17e1a1e5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Export.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } }, setInstance: (i) => { instance = i; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js index 882e633e..e8d18b98 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_check"] = function bjs_check(a, b) { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js index 7c20fa15..c7efcf0d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Export.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } }, setInstance: (i) => { instance = i; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js index 481cc495..24fa28a0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkNumber"] = function bjs_checkNumber() { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.Export.js index bbfbb0ac..bc9748d8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.Export.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts index 9e64ddff..b7fddd42 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.d.ts @@ -20,10 +20,24 @@ export interface MyViewControllerDelegate { eventCount: number; readonly delegateName: string; optionalName: string | null; - myEnum: ExampleEnumTag; - result: ResultTag | null; + optionalRawEnum: ExampleEnumTag | null; + rawStringEnum: ExampleEnumTag; + result: ResultTag; + optionalResult: ResultTag | null; + direction: DirectionTag; + directionOptional: DirectionTag | null; + priority: PriorityTag; + priorityOptional: PriorityTag | null; } +export const DirectionValues: { + readonly North: 0; + readonly South: 1; + readonly East: 2; + readonly West: 3; +}; +export type DirectionTag = typeof DirectionValues[keyof typeof DirectionValues]; + export const ExampleEnumValues: { readonly Test: "test"; readonly Test2: "test2"; @@ -40,10 +54,21 @@ export const ResultValues: { export type ResultTag = { tag: typeof ResultValues.Tag.Success; param0: string } | { tag: typeof ResultValues.Tag.Failure; param0: number } +export const PriorityValues: { + readonly Low: -1; + readonly Medium: 0; + readonly High: 1; +}; +export type PriorityTag = typeof PriorityValues[keyof typeof PriorityValues]; + +export type DirectionObject = typeof DirectionValues; + export type ExampleEnumObject = typeof ExampleEnumValues; export type ResultObject = typeof ResultValues; +export type PriorityObject = typeof PriorityValues; + /// Represents a Swift heap object like a class instance or an actor instance. export interface SwiftHeapObject { /// Release the heap object. @@ -72,8 +97,10 @@ export type Exports = { MyViewController: { new(delegate: MyViewControllerDelegate): MyViewController; } + Direction: DirectionObject ExampleEnum: ExampleEnumObject Result: ResultObject + Priority: PriorityObject } export type Imports = { } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js index 8aa18d39..2740c7c2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.Export.js @@ -4,6 +4,13 @@ // To update this file, just rebuild your project or run // `swift package bridge-js`. +export const DirectionValues = { + North: 0, + South: 1, + East: 2, + West: 3, +}; + export const ExampleEnumValues = { Test: "test", Test2: "test2", @@ -55,6 +62,12 @@ const __bjs_createResultValuesHelpers = () => { } }); }; +export const PriorityValues = { + Low: -1, + Medium: 0, + High: 1, +}; + export async function createInstantiator(options, swift) { let instance; let memory; @@ -190,6 +203,41 @@ export async function createInstantiator(options, swift) { 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; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; @@ -231,15 +279,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_MyViewControllerDelegate_optionalName_get"] = function bjs_MyViewControllerDelegate_optionalName_get(self) { try { let ret = swift.memory.getObject(self).optionalName; - const isSome = ret != null; - if (isSome) { - const bytes = textEncoder.encode(ret); - bjs["swift_js_return_optional_string"](1, bytes, bytes.length); - return bytes.length; - } else { - bjs["swift_js_return_optional_string"](0, 0, 0); - return -1; - } + tmpRetString = ret; } catch (error) { setException(error); } @@ -256,20 +296,40 @@ export async function createInstantiator(options, swift) { setException(error); } } - TestModule["bjs_MyViewControllerDelegate_myEnum_get"] = function bjs_MyViewControllerDelegate_myEnum_get(self) { + TestModule["bjs_MyViewControllerDelegate_optionalRawEnum_get"] = function bjs_MyViewControllerDelegate_optionalRawEnum_get(self) { try { - let ret = swift.memory.getObject(self).myEnum; + let ret = swift.memory.getObject(self).optionalRawEnum; + tmpRetString = ret; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_optionalRawEnum_set"] = function bjs_MyViewControllerDelegate_optionalRawEnum_set(self, valueIsSome, valueWrappedValue) { + try { + let obj; + if (valueIsSome) { + obj = swift.memory.getObject(valueWrappedValue); + swift.memory.release(valueWrappedValue); + } + swift.memory.getObject(self).optionalRawEnum = valueIsSome ? obj : null; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_rawStringEnum_get"] = function bjs_MyViewControllerDelegate_rawStringEnum_get(self) { + try { + let ret = swift.memory.getObject(self).rawStringEnum; tmpRetBytes = textEncoder.encode(ret); return tmpRetBytes.length; } catch (error) { setException(error); } } - TestModule["bjs_MyViewControllerDelegate_myEnum_set"] = function bjs_MyViewControllerDelegate_myEnum_set(self, value) { + TestModule["bjs_MyViewControllerDelegate_rawStringEnum_set"] = function bjs_MyViewControllerDelegate_rawStringEnum_set(self, value) { try { const valueObject = swift.memory.getObject(value); swift.memory.release(value); - swift.memory.getObject(self).myEnum = valueObject; + swift.memory.getObject(self).rawStringEnum = valueObject; } catch (error) { setException(error); } @@ -277,20 +337,104 @@ export async function createInstantiator(options, swift) { TestModule["bjs_MyViewControllerDelegate_result_get"] = function bjs_MyViewControllerDelegate_result_get(self) { try { let ret = swift.memory.getObject(self).result; + const { caseId: caseId, cleanup: cleanup } = enumHelpers.Result.lower(ret); + return caseId; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_result_set"] = function bjs_MyViewControllerDelegate_result_set(self, value) { + try { + const enumValue = enumHelpers.Result.raise(value, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s); + swift.memory.getObject(self).result = enumValue; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_optionalResult_get"] = function bjs_MyViewControllerDelegate_optionalResult_get(self) { + try { + let ret = swift.memory.getObject(self).optionalResult; const isSome = ret != null; if (isSome) { const { caseId: caseId, cleanup: cleanup } = enumHelpers.Result.lower(ret); - bjs["swift_js_return_optional_int"](1, caseId); + return caseId; } else { - bjs["swift_js_return_optional_int"](0, 0); + return -1; } } catch (error) { setException(error); } } - TestModule["bjs_MyViewControllerDelegate_result_set"] = function bjs_MyViewControllerDelegate_result_set(self, valueIsSome, valueWrappedValue) { + TestModule["bjs_MyViewControllerDelegate_optionalResult_set"] = function bjs_MyViewControllerDelegate_optionalResult_set(self, valueIsSome, valueWrappedValue) { + try { + let enumValue; + if (valueIsSome) { + enumValue = enumHelpers.Result.raise(valueWrappedValue, tmpRetStrings, tmpRetInts, tmpRetF32s, tmpRetF64s); + } + swift.memory.getObject(self).optionalResult = valueIsSome ? enumValue : null; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_direction_get"] = function bjs_MyViewControllerDelegate_direction_get(self) { + try { + let ret = swift.memory.getObject(self).direction; + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_MyViewControllerDelegate_direction_set"] = function bjs_MyViewControllerDelegate_direction_set(self, value) { + try { + swift.memory.getObject(self).direction = value; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_directionOptional_get"] = function bjs_MyViewControllerDelegate_directionOptional_get(self) { + try { + let ret = swift.memory.getObject(self).directionOptional; + const isSome = ret != null; + return isSome ? (ret | 0) : -1; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_directionOptional_set"] = function bjs_MyViewControllerDelegate_directionOptional_set(self, valueIsSome, valueWrappedValue) { + try { + swift.memory.getObject(self).directionOptional = valueIsSome ? valueWrappedValue : null; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_priority_get"] = function bjs_MyViewControllerDelegate_priority_get(self) { + try { + let ret = swift.memory.getObject(self).priority; + return ret; + } catch (error) { + setException(error); + return 0 + } + } + TestModule["bjs_MyViewControllerDelegate_priority_set"] = function bjs_MyViewControllerDelegate_priority_set(self, value) { + try { + swift.memory.getObject(self).priority = value; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_priorityOptional_get"] = function bjs_MyViewControllerDelegate_priorityOptional_get(self) { + try { + let ret = swift.memory.getObject(self).priorityOptional; + tmpRetOptionalInt = ret; + } catch (error) { + setException(error); + } + } + TestModule["bjs_MyViewControllerDelegate_priorityOptional_set"] = function bjs_MyViewControllerDelegate_priorityOptional_set(self, valueIsSome, valueWrappedValue) { try { - swift.memory.getObject(self).result = valueIsSome ? valueWrappedValue : null; + swift.memory.getObject(self).priorityOptional = valueIsSome ? valueWrappedValue : null; } catch (error) { setException(error); } @@ -367,7 +511,6 @@ export async function createInstantiator(options, swift) { try { let ret = swift.memory.getObject(self).createOptionalHelper(); const isSome = ret != null; - return isSome ? ret.pointer : 0; } catch (error) { setException(error); } @@ -513,8 +656,10 @@ export async function createInstantiator(options, swift) { return { Helper, MyViewController, + Direction: DirectionValues, ExampleEnum: ExampleEnumValues, Result: ResultValues, + Priority: PriorityValues, }; }, } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Export.js index 44ad0a93..6fa84a4f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Export.js @@ -190,6 +190,41 @@ export async function createInstantiator(options, swift) { 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; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Export.js index eb1c5ad1..29060b93 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Export.js @@ -143,6 +143,41 @@ export async function createInstantiator(options, swift) { 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; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js index b7d4b505..a9f4bcd7 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Export.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } }, setInstance: (i) => { instance = i; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js index bc109fc9..4f6e1dae 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkString"] = function bjs_checkString(a) { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js index 08eef7e0..2d9a848f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Export.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } }, setInstance: (i) => { instance = i; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js index 11d30446..80d4fcd9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkString"] = function bjs_checkString() { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js index 0a545a0e..395057d8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.Export.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } // Wrapper functions for module: TestModule if (!importObject["TestModule"]) { importObject["TestModule"] = {}; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js index 453d5f76..a1d39cd2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TS2SkeletonLike.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_createTS2Skeleton"] = function bjs_createTS2Skeleton() { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js index af17ab14..f2e0bfc9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.Export.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } }, setInstance: (i) => { instance = i; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js index 9ba7cf60..7c4438b0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeAlias.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_checkSimple"] = function bjs_checkSimple(a) { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js index 98fb575d..49b0b331 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/TypeScriptClass.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_Greeter_init"] = function bjs_Greeter_init(name) { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js index d2716dfa..a0f6f0dd 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Export.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } }, setInstance: (i) => { instance = i; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js index 4b4c75ea..bd1d9bfb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.Import.js @@ -138,6 +138,41 @@ export async function createInstantiator(options, swift) { 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; + } const TestModule = importObject["TestModule"] = importObject["TestModule"] || {}; TestModule["bjs_check"] = function bjs_check() { try { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/DefaultParameters.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/DefaultParameters.swift index fd382c0a..675f7bfb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/DefaultParameters.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/DefaultParameters.swift @@ -11,13 +11,13 @@ extension Status: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Status { - return Status(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Status { return Status(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift index ce952ca9..0c70fe5c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumAssociatedValue.swift @@ -7,8 +7,6 @@ @_spi(BridgeJS) import JavaScriptKit extension APIResult: _BridgedSwiftAssociatedValueEnum { - // MARK: Private Helper - private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> APIResult { switch caseId { case 0: @@ -55,8 +53,7 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> APIResult { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> APIResult { return _bridgeJSLiftFromCaseId(caseId) } @@ -93,8 +90,6 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } extension ComplexResult: _BridgedSwiftAssociatedValueEnum { - // MARK: Private Helper - private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> ComplexResult { switch caseId { case 0: @@ -169,8 +164,7 @@ extension ComplexResult: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> ComplexResult { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> ComplexResult { return _bridgeJSLiftFromCaseId(caseId) } @@ -235,8 +229,6 @@ extension ComplexResult: _BridgedSwiftAssociatedValueEnum { } extension Utilities.Result: _BridgedSwiftAssociatedValueEnum { - // MARK: Private Helper - private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> Utilities.Result { switch caseId { case 0: @@ -278,8 +270,7 @@ extension Utilities.Result: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> Utilities.Result { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> Utilities.Result { return _bridgeJSLiftFromCaseId(caseId) } @@ -317,8 +308,6 @@ extension Utilities.Result: _BridgedSwiftAssociatedValueEnum { } extension NetworkingResult: _BridgedSwiftAssociatedValueEnum { - // MARK: Private Helper - private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> NetworkingResult { switch caseId { case 0: @@ -350,8 +339,7 @@ extension NetworkingResult: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> NetworkingResult { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> NetworkingResult { return _bridgeJSLiftFromCaseId(caseId) } @@ -381,8 +369,6 @@ extension NetworkingResult: _BridgedSwiftAssociatedValueEnum { } extension APIOptionalResult: _BridgedSwiftAssociatedValueEnum { - // MARK: Private Helper - private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> APIOptionalResult { switch caseId { case 0: @@ -445,8 +431,7 @@ extension APIOptionalResult: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> APIOptionalResult { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> APIOptionalResult { return _bridgeJSLiftFromCaseId(caseId) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumCase.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumCase.swift index 4a1be41e..06bfa86a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumCase.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumCase.swift @@ -11,13 +11,13 @@ extension Direction: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Direction { - return Direction(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Direction { return Direction(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -54,13 +54,13 @@ extension Status: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Status { - return Status(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Status { return Status(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -93,13 +93,13 @@ extension TSDirection: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> TSDirection { - return TSDirection(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> TSDirection { return TSDirection(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -136,13 +136,13 @@ extension PublicStatus: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> PublicStatus { - return PublicStatus(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> PublicStatus { return PublicStatus(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumNamespace.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumNamespace.swift index daa5577a..ca201f3d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumNamespace.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/EnumNamespace.swift @@ -11,13 +11,13 @@ extension Networking.API.Method: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Networking.API.Method { - return Networking.API.Method(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Networking.API.Method { return Networking.API.Method(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -60,13 +60,13 @@ extension Internal.SupportedMethod: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Internal.SupportedMethod { - return Internal.SupportedMethod(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Internal.SupportedMethod { return Internal.SupportedMethod(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json index bddcf2aa..46b96429 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.json @@ -250,6 +250,43 @@ } ], "enums" : [ + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "north" + }, + { + "associatedValues" : [ + + ], + "name" : "south" + }, + { + "associatedValues" : [ + + ], + "name" : "east" + }, + { + "associatedValues" : [ + + ], + "name" : "west" + } + ], + "emitStyle" : "const", + "name" : "Direction", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Direction" + }, { "cases" : [ { @@ -314,6 +351,41 @@ ], "swiftCallName" : "Result" + }, + { + "cases" : [ + { + "associatedValues" : [ + + ], + "name" : "low", + "rawValue" : "-1" + }, + { + "associatedValues" : [ + + ], + "name" : "medium", + "rawValue" : "0" + }, + { + "associatedValues" : [ + + ], + "name" : "high", + "rawValue" : "1" + } + ], + "emitStyle" : "const", + "name" : "Priority", + "rawType" : "Int", + "staticMethods" : [ + + ], + "staticProperties" : [ + + ], + "swiftCallName" : "Priority" } ], "functions" : [ @@ -629,7 +701,21 @@ }, { "isReadonly" : false, - "name" : "myEnum", + "name" : "optionalRawEnum", + "type" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "ExampleEnum", + "_1" : "String" + } + } + } + } + }, + { + "isReadonly" : false, + "name" : "rawStringEnum", "type" : { "rawValueEnum" : { "_0" : "ExampleEnum", @@ -640,6 +726,15 @@ { "isReadonly" : false, "name" : "result", + "type" : { + "associatedValueEnum" : { + "_0" : "Result" + } + } + }, + { + "isReadonly" : false, + "name" : "optionalResult", "type" : { "optional" : { "_0" : { @@ -649,6 +744,52 @@ } } } + }, + { + "isReadonly" : false, + "name" : "direction", + "type" : { + "caseEnum" : { + "_0" : "Direction" + } + } + }, + { + "isReadonly" : false, + "name" : "directionOptional", + "type" : { + "optional" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + } + }, + { + "isReadonly" : false, + "name" : "priority", + "type" : { + "rawValueEnum" : { + "_0" : "Priority", + "_1" : "Int" + } + } + }, + { + "isReadonly" : false, + "name" : "priorityOptional", + "type" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Priority", + "_1" : "Int" + } + } + } + } } ] } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift index 8bd37e8e..d68ef81d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/Protocol.swift @@ -56,8 +56,9 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto func onOptionalHelperUpdated(_ helper: Optional) { @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_onOptionalHelperUpdated") - func _extern_onOptionalHelperUpdated(this: Int32, helper: UnsafeMutableRawPointer) - _extern_onOptionalHelperUpdated(this: Int32(bitPattern: jsObject.id), helper: helper.bridgeJSLowerParameter()) + func _extern_onOptionalHelperUpdated(this: Int32, helperIsSome: Int32, helperPointer: UnsafeMutableRawPointer) + let (helperIsSome, helperPointer) = helper.bridgeJSLowerParameterWithPresence() + _extern_onOptionalHelperUpdated(this: Int32(bitPattern: jsObject.id), helperIsSome: helperIsSome, helperPointer: helperPointer) } func createOptionalHelper() -> Optional { @@ -82,9 +83,9 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto func getResult() -> Result { @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_getResult") - func _extern_getResult(this: Int32) - _extern_getResult(this: Int32(bitPattern: jsObject.id)) - return Result.bridgeJSLiftReturn() + func _extern_getResult(this: Int32) -> Int32 + let ret = _extern_getResult(this: Int32(bitPattern: jsObject.id)) + return Result.bridgeJSLiftReturn(ret) } var eventCount: Int { @@ -113,56 +114,186 @@ struct AnyMyViewControllerDelegate: MyViewControllerDelegate, _BridgedSwiftProto var optionalName: Optional { get { @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_optionalName_get") - func _extern_get(this: Int32) -> Int32 - let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) - return Optional.bridgeJSLiftReturn(ret) + func _extern_get(this: Int32) + _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturnFromSideChannel() } set { @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_optionalName_set") - func _extern_set(this: Int32, value: Int32) - _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + func _extern_set(this: Int32, isSome: Int32, value: Int32) + let (isSome, value) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, value: value) + } + } + + var optionalRawEnum: Optional { + get { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_optionalRawEnum_get") + func _extern_get(this: Int32) + _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturnFromSideChannel() + } + set { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_optionalRawEnum_set") + func _extern_set(this: Int32, isSome: Int32, value: Int32) + let (isSome, value) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, value: value) } } - var myEnum: ExampleEnum { + var rawStringEnum: ExampleEnum { get { - @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_myEnum_get") + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_rawStringEnum_get") func _extern_get(this: Int32) -> Int32 let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) return ExampleEnum.bridgeJSLiftReturn(ret) } set { - @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_myEnum_set") + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_rawStringEnum_set") func _extern_set(this: Int32, value: Int32) _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) } } - var result: Optional { + var result: Result { get { @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_result_get") - func _extern_get(this: Int32) - _extern_get(this: Int32(bitPattern: jsObject.id)) - return Optional.bridgeJSLiftReturn() + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Result.bridgeJSLiftReturn(ret) } set { @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_result_set") + func _extern_set(this: Int32, caseId: Int32) + _extern_set(this: Int32(bitPattern: jsObject.id), caseId: newValue.bridgeJSLowerParameter()) + } + } + + var optionalResult: Optional { + get { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_optionalResult_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_optionalResult_set") + func _extern_set(this: Int32, isSome: Int32, caseId: Int32) + let (isSome, caseId) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, caseId: caseId) + } + } + + var direction: Direction { + get { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_direction_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Direction.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_direction_set") + func _extern_set(this: Int32, value: Int32) + _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + } + } + + var directionOptional: Optional { + get { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_directionOptional_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_directionOptional_set") + func _extern_set(this: Int32, isSome: Int32, value: Int32) + let (isSome, value) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, value: value) + } + } + + var priority: Priority { + get { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_priority_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Priority.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_priority_set") func _extern_set(this: Int32, value: Int32) _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) } } + var priorityOptional: Optional { + get { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_priorityOptional_get") + func _extern_get(this: Int32) + _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturnFromSideChannel() + } + set { + @_extern(wasm, module: "TestModule", name: "bjs_MyViewControllerDelegate_priorityOptional_set") + func _extern_set(this: Int32, isSome: Int32, value: Int32) + let (isSome, value) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, value: value) + } + } + static func bridgeJSLiftParameter(_ value: Int32) -> Self { return AnyMyViewControllerDelegate(jsObject: JSObject(id: UInt32(bitPattern: value))) } } +extension Direction: _BridgedSwiftCaseEnum { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameter() -> Int32 { + return bridgeJSRawValue + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Direction { + return bridgeJSLiftParameter(value) + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Direction { + return Direction(bridgeJSRawValue: value)! + } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { + return bridgeJSLowerParameter() + } + + private init?(bridgeJSRawValue: Int32) { + switch bridgeJSRawValue { + case 0: + self = .north + case 1: + self = .south + case 2: + self = .east + case 3: + self = .west + default: + return nil + } + } + + private var bridgeJSRawValue: Int32 { + switch self { + case .north: + return 0 + case .south: + return 1 + case .east: + return 2 + case .west: + return 3 + } + } +} + extension ExampleEnum: _BridgedSwiftEnumNoPayload { } extension Result: _BridgedSwiftAssociatedValueEnum { - // MARK: Private Helper - private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> Result { switch caseId { case 0: @@ -190,8 +321,7 @@ extension Result: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> Result { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> Result { return _bridgeJSLiftFromCaseId(caseId) } @@ -216,6 +346,9 @@ extension Result: _BridgedSwiftAssociatedValueEnum { } } +extension Priority: _BridgedSwiftEnumNoPayload { +} + @_expose(wasm, "bjs_Helper_init") @_cdecl("bjs_Helper_init") public func _bjs_Helper_init(value: Int32) -> UnsafeMutableRawPointer { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticFunctions.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticFunctions.swift index a26d5ea1..7aa91b91 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticFunctions.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticFunctions.swift @@ -11,13 +11,13 @@ extension Calculator: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> Calculator { - return Calculator(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> Calculator { return Calculator(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { @@ -53,8 +53,6 @@ public func _bjs_Calculator_static_square(value: Int32) -> Int32 { } extension APIResult: _BridgedSwiftAssociatedValueEnum { - // MARK: Private Helper - private static func _bridgeJSLiftFromCaseId(_ caseId: Int32) -> APIResult { switch caseId { case 0: @@ -82,8 +80,7 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> APIResult { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> APIResult { return _bridgeJSLiftFromCaseId(caseId) } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticProperties.swift b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticProperties.swift index 6edd0c8f..72d561a0 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticProperties.swift +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/ExportSwiftTests/StaticProperties.swift @@ -11,13 +11,13 @@ extension PropertyEnum: _BridgedSwiftCaseEnum { return bridgeJSRawValue } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ value: Int32) -> PropertyEnum { - return PropertyEnum(bridgeJSRawValue: value)! + return bridgeJSLiftParameter(value) } @_spi(BridgeJS) @_transparent public static func bridgeJSLiftParameter(_ value: Int32) -> PropertyEnum { return PropertyEnum(bridgeJSRawValue: value)! } @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerReturn() -> Int32 { - return bridgeJSRawValue + return bridgeJSLowerParameter() } private init?(bridgeJSRawValue: Int32) { diff --git a/Sources/JavaScriptKit/BridgeJSInstrincics.swift b/Sources/JavaScriptKit/BridgeJSInstrincics.swift index be6e7b47..9c97583c 100644 --- a/Sources/JavaScriptKit/BridgeJSInstrincics.swift +++ b/Sources/JavaScriptKit/BridgeJSInstrincics.swift @@ -77,6 +77,10 @@ import _CJavaScriptKit // - `func bridgeJSLiftParameter(_ ...) -> <#TargetType#>`: lift the given Wasm core type parameters to a higher-level type // - `func bridgeJSLowerReturn() -> <#WasmCoreType#>`: lower the given higher-level return value to a Wasm core type // +// Optional types (ExportSwift only) additionally define: +// - `func bridgeJSLowerParameterWithPresence()`: lower optional as (isSome, value) tuple for protocol setters/parameters +// - `func bridgeJSLiftReturnFromSideChannel()`: lift optional from side-channel storage for protocol property getters +// // See JSGlueGen.swift in BridgeJSLink for JS-side lowering/lifting implementation. /// A protocol that Swift types that can appear as parameters or return values on @@ -340,7 +344,7 @@ public protocol _BridgedSwiftCaseEnum { public protocol _BridgedSwiftAssociatedValueEnum: _BridgedSwiftTypeLoweredIntoVoidType { // MARK: ImportTS @_spi(BridgeJS) consuming func bridgeJSLowerParameter() -> Int32 - @_spi(BridgeJS) static func bridgeJSLiftReturn() -> Self + @_spi(BridgeJS) static func bridgeJSLiftReturn(_ caseId: Int32) -> Self // MARK: ExportSwift @_spi(BridgeJS) static func bridgeJSLiftParameter(_ caseId: Int32) -> Self @@ -464,21 +468,25 @@ where Self: RawRepresentable, RawValue: _BridgedSwiftTypeLoweredIntoSingleWasmCo } #endif -// MARK: Optional Type Support - extension Optional where Wrapped == Bool { // MARK: ImportTS @available(*, unavailable, message: "Optional Bool type is not supported to be passed to imported JS functions") @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Void {} - @available(*, unavailable, message: "Optional Bool type is not supported to be passed to imported JS functions") - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ wrappedValue: Int32) -> Bool? { - return nil - } - // MARK: ExportSwift + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithPresence() -> ( + isSome: Int32, value: Int32 + ) { + switch consume self { + case .none: + return (isSome: 0, value: 0) + case .some(let wrapped): + return (isSome: 1, value: wrapped.bridgeJSLowerParameter()) + } + } + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Bool? { if isSome == 0 { return nil @@ -487,6 +495,19 @@ extension Optional where Wrapped == Bool { } } + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Bool? { + switch value { + case -1: + return nil + case 0: + return false + case 1: + return true + default: + return nil // Treat invalid values as null + } + } + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_return_optional_bool") @@ -507,18 +528,25 @@ extension Optional where Wrapped == Bool { } } -/// Optional support for Int extension Optional where Wrapped == Int { // MARK: ImportTS @available(*, unavailable, message: "Optional Int type is not supported to be passed to imported JS functions") @_spi(BridgeJS) public func bridgeJSLowerParameter() -> Void {} - @available(*, unavailable, message: "Optional Int type is not supported to be passed to imported JS functions") - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ wrappedValue: Int32) -> Int? { return nil } - // MARK: ExportSwift + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithPresence() -> ( + isSome: Int32, value: Int32 + ) { + switch consume self { + case .none: + return (isSome: 0, value: 0) + case .some(let wrapped): + return (isSome: 1, value: wrapped.bridgeJSLowerParameter()) + } + } + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Int? { if isSome == 0 { return nil @@ -527,6 +555,29 @@ extension Optional where Wrapped == Int { } } + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Int? { + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_int_presence") + func _swift_js_get_optional_int_presence() -> Int32 + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_int_value") + func _swift_js_get_optional_int_value() -> Int32 + #else + func _swift_js_get_optional_int_presence() -> Int32 { + _onlyAvailableOnWasm() + } + func _swift_js_get_optional_int_value() -> Int32 { + _onlyAvailableOnWasm() + } + #endif + + let isSome = _swift_js_get_optional_int_presence() + if isSome == 0 { + return nil + } else { + return Int.bridgeJSLiftReturn(_swift_js_get_optional_int_value()) + } + } + @_spi(BridgeJS) public func bridgeJSLowerReturn() -> Void { #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_return_optional_int") @@ -547,34 +598,43 @@ extension Optional where Wrapped == Int { } } extension Optional where Wrapped == String { - // MARK: ImportTS + // MARK: ExportSwift - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithPresence() -> ( + isSome: Int32, value: Int32 + ) { switch consume self { case .none: - return 0 - case .some(let value): - return value.bridgeJSLowerParameter() + return (isSome: 0, value: 0) + case .some(let wrapped): + return (isSome: 1, value: wrapped.bridgeJSLowerParameter()) } } - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ length: Int32) -> String? { - // JavaScript returns -1 for null, or the byte length if present - // The actual string is already in tmpRetString side channel - if length < 0 { + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ bytes: Int32, _ count: Int32) -> String? + { + if isSome == 0 { return nil + } else { + return String.bridgeJSLiftParameter(bytes, count) } - return String.bridgeJSLiftReturn(length) } - // MARK: ExportSwift + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> String? { + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_string") + func _swift_js_get_optional_string() -> Int32 + #else + func _swift_js_get_optional_string() -> Int32 { + _onlyAvailableOnWasm() + } + #endif - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ bytes: Int32, _ count: Int32) -> String? - { - if isSome == 0 { + let length = _swift_js_get_optional_string() + if length < 0 { return nil } else { - return String.bridgeJSLiftParameter(bytes, count) + return String.bridgeJSLiftReturn(length) } } @@ -600,18 +660,19 @@ extension Optional where Wrapped == String { } } extension Optional where Wrapped == JSObject { - // MARK: ImportTS - - @available(*, unavailable, message: "Optional JSObject type is not supported to be passed to imported JS functions") - @_spi(BridgeJS) public func bridgeJSLowerParameter() -> Void {} + // MARK: ExportSwift - @available(*, unavailable, message: "Optional JSObject type is not supported to be passed to imported JS functions") - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ objectId: Int32) -> JSObject? { - return nil + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithPresence() -> ( + isSome: Int32, value: Int32 + ) { + switch consume self { + case .none: + return (isSome: 0, value: 0) + case .some(let wrapped): + return (isSome: 1, value: wrapped.bridgeJSLowerParameter()) + } } - // MARK: ExportSwift - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ objectId: Int32) -> JSObject? { if isSome == 0 { return nil @@ -642,24 +703,6 @@ extension Optional where Wrapped == JSObject { } extension Optional where Wrapped: _BridgedSwiftProtocolWrapper { - // MARK: ImportTS - - @available( - *, - unavailable, - message: "Optional protocol types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public func bridgeJSLowerParameter() -> Void {} - - @available( - *, - unavailable, - message: "Optional protocol types are not supported to be passed to imported JS functions" - ) - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ objectId: Int32) -> Wrapped? { - return nil - } - // MARK: ExportSwift @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ objectId: Int32) -> Wrapped? { @@ -705,6 +748,17 @@ extension Optional where Wrapped: _BridgedSwiftHeapObject { } } + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithPresence() -> ( + isSome: Int32, pointer: UnsafeMutableRawPointer + ) { + switch consume self { + case .none: + return (isSome: 0, pointer: UnsafeMutableRawPointer(bitPattern: 0)!) + case .some(let value): + return (isSome: 1, pointer: value.bridgeJSLowerParameter()) + } + } + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ pointer: UnsafeMutableRawPointer) -> Wrapped? { if pointer == UnsafeMutableRawPointer(bitPattern: 0) { @@ -753,11 +807,6 @@ extension Optional where Wrapped == Float { @available(*, unavailable, message: "Optional Float type is not supported to be passed to imported JS functions") @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Void {} - @available(*, unavailable, message: "Optional Float type is not supported to be passed to imported JS functions") - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ wrappedValue: Float32) -> Float? { - return nil - } - // MARK: ExportSwift @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Float32) -> Float? { @@ -768,6 +817,29 @@ extension Optional where Wrapped == Float { } } + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Float? { + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_float_presence") + func _swift_js_get_optional_float_presence() -> Int32 + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_float_value") + func _swift_js_get_optional_float_value() -> Float32 + #else + func _swift_js_get_optional_float_presence() -> Int32 { + _onlyAvailableOnWasm() + } + func _swift_js_get_optional_float_value() -> Float32 { + _onlyAvailableOnWasm() + } + #endif + + let isSome = _swift_js_get_optional_float_presence() + if isSome == 0 { + return nil + } else { + return Float.bridgeJSLiftReturn(_swift_js_get_optional_float_value()) + } + } + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_return_optional_float") @@ -795,11 +867,6 @@ extension Optional where Wrapped == Double { @available(*, unavailable, message: "Optional Double type is not supported to be passed to imported JS functions") @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Void {} - @available(*, unavailable, message: "Optional Double type is not supported to be passed to imported JS functions") - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ isSome: Int32, _ wrappedValue: Float64) -> Double? { - return nil - } - // MARK: ExportSwift @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Float64) -> Double? { @@ -810,6 +877,29 @@ extension Optional where Wrapped == Double { } } + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Double? { + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_double_presence") + func _swift_js_get_optional_double_presence() -> Int32 + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_double_value") + func _swift_js_get_optional_double_value() -> Float64 + #else + func _swift_js_get_optional_double_presence() -> Int32 { + _onlyAvailableOnWasm() + } + func _swift_js_get_optional_double_value() -> Float64 { + _onlyAvailableOnWasm() + } + #endif + + let isSome = _swift_js_get_optional_double_presence() + if isSome == 0 { + return nil + } else { + return Double.bridgeJSLiftReturn(_swift_js_get_optional_double_value()) + } + } + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_return_optional_double") @@ -832,32 +922,30 @@ extension Optional where Wrapped == Double { /// Optional support for case enums extension Optional where Wrapped: _BridgedSwiftCaseEnum { - // MARK: ImportTS + // MARK: ExportSwift - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameterWithPresence() -> (isSome: Int32, value: Int32) { switch consume self { case .none: - return -1 // Sentinel for nil + return (isSome: 0, value: 0) case .some(let value): - return value.bridgeJSLowerParameter() + return (isSome: 1, value: value.bridgeJSLowerParameter()) } } - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Wrapped? { - if value == -1 { + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Wrapped? { + if isSome == 0 { return nil } else { - return Wrapped.bridgeJSLiftReturn(value) + return Wrapped.bridgeJSLiftParameter(wrappedValue) } } - // MARK: ExportSwift - - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Wrapped? { - if isSome == 0 { + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Wrapped? { + if value == -1 { return nil } else { - return Wrapped.bridgeJSLiftParameter(wrappedValue) + return Wrapped.bridgeJSLiftReturn(value) } } @@ -900,28 +988,19 @@ extension Optional where Wrapped: _BridgedSwiftTypeLoweredIntoVoidType { // MARK: Optional Raw Value Enum Support extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == String { - // MARK: ImportTS + // MARK: ExportSwift - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithPresence() -> ( + isSome: Int32, value: Int32 + ) { switch consume self { case .none: - return 0 // Sentinel for nil - case .some(let value): - return value.bridgeJSLowerParameter() + return (isSome: 0, value: 0) + case .some(let wrapped): + return (isSome: 1, value: wrapped.bridgeJSLowerParameter()) } } - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ length: Int32) -> Wrapped? { - if length == 0 { - return nil - } else { - let rawValue = String.bridgeJSLiftReturn(length) - return Wrapped(rawValue: rawValue) - } - } - - // MARK: ExportSwift - @_spi(BridgeJS) public static func bridgeJSLiftParameter( _ isSome: Int32, _ bytes: Int32, @@ -931,6 +1010,25 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres return optionalRawValue.flatMap { Wrapped(rawValue: $0) } } + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Wrapped? { + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_string") + func _swift_js_get_optional_string() -> Int32 + #else + func _swift_js_get_optional_string() -> Int32 { + _onlyAvailableOnWasm() + } + #endif + + let length = _swift_js_get_optional_string() + if length < 0 { + return nil + } else { + let rawValue = String.bridgeJSLiftReturn(length) + return Wrapped(rawValue: rawValue) + } + } + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { let optionalRawValue: String? = self?.rawValue optionalRawValue.bridgeJSLowerReturn() @@ -938,58 +1036,52 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres } extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Int { - // MARK: ImportTS - - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + // MARK: ExportSwift + @_spi(BridgeJS) public consuming func bridgeJSLowerParameterWithPresence() -> (isSome: Int32, value: Int32) { switch consume self { case .none: - return -1 // Sentinel for nil + return (isSome: 0, value: 0) case .some(let value): - return value.bridgeJSLowerParameter() + return (isSome: 1, value: value.bridgeJSLowerParameter()) } } - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Wrapped? { - if value == -1 { - return nil - } else { - return Wrapped(rawValue: Int(value)) - } - } - - // MARK: ExportSwift - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Wrapped? { let optionalRawValue = Int?.bridgeJSLiftParameter(isSome, wrappedValue) return optionalRawValue.flatMap { Wrapped(rawValue: $0) } } - @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { - let optionalRawValue: Int? = self?.rawValue - optionalRawValue.bridgeJSLowerReturn() - } -} - -extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Bool { - // MARK: ImportTS - - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { - switch consume self { - case .none: - return -1 // Sentinel for nil - case .some(let value): - return value.bridgeJSLowerParameter() + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Wrapped? { + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_int_presence") + func _swift_js_get_optional_int_presence() -> Int32 + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_int_value") + func _swift_js_get_optional_int_value() -> Int32 + #else + func _swift_js_get_optional_int_presence() -> Int32 { + _onlyAvailableOnWasm() } - } + func _swift_js_get_optional_int_value() -> Int32 { + _onlyAvailableOnWasm() + } + #endif - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Int32) -> Wrapped? { - if value == -1 { + let isSome = _swift_js_get_optional_int_presence() + if isSome == 0 { return nil } else { - return Wrapped(rawValue: value != 0) + let rawValue = _swift_js_get_optional_int_value() + return Wrapped(rawValue: Int(rawValue)) } } + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { + let optionalRawValue: Int? = self?.rawValue + optionalRawValue.bridgeJSLowerReturn() + } +} + +extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Bool { // MARK: ExportSwift @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Int32) -> Wrapped? { @@ -1004,31 +1096,46 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres } extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Float { - // MARK: ImportTS + // MARK: ExportSwift - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Float32 { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithPresence() -> ( + isSome: Int32, value: Float32 + ) { switch consume self { case .none: - return Float32.nan // Sentinel for nil (NaN) - case .some(let value): - return value.bridgeJSLowerParameter() - } - } - - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Float32) -> Wrapped? { - if value.isNaN { - return nil - } else { - return Wrapped(rawValue: Float(value)) + return (isSome: 0, value: 0.0) + case .some(let wrapped): + return (isSome: 1, value: wrapped.bridgeJSLowerParameter()) } } - // MARK: ExportSwift - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Float32) -> Wrapped? { let optionalRawValue = Float?.bridgeJSLiftParameter(isSome, wrappedValue) return optionalRawValue.flatMap { Wrapped(rawValue: $0) } } + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Wrapped? { + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_float_presence") + func _swift_js_get_optional_float_presence() -> Int32 + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_float_value") + func _swift_js_get_optional_float_value() -> Float32 + #else + func _swift_js_get_optional_float_presence() -> Int32 { + _onlyAvailableOnWasm() + } + func _swift_js_get_optional_float_value() -> Float32 { + _onlyAvailableOnWasm() + } + #endif + + let isSome = _swift_js_get_optional_float_presence() + if isSome == 0 { + return nil + } else { + let rawValue = _swift_js_get_optional_float_value() + return Wrapped(rawValue: Float(rawValue)) + } + } @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { let optionalRawValue: Float? = self?.rawValue @@ -1037,32 +1144,48 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres } extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepresentable, Wrapped.RawValue == Double { - // MARK: ImportTS + // MARK: ExportSwift - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Float64 { + @_spi(BridgeJS) @_transparent public consuming func bridgeJSLowerParameterWithPresence() -> ( + isSome: Int32, value: Float64 + ) { switch consume self { case .none: - return Float64.nan // Sentinel for nil (NaN) - case .some(let value): - return value.bridgeJSLowerParameter() + return (isSome: 0, value: 0.0) + case .some(let wrapped): + return (isSome: 1, value: wrapped.bridgeJSLowerParameter()) } } - @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ value: Float64) -> Wrapped? { - if value.isNaN { - return nil - } else { - return Wrapped(rawValue: Double(value)) - } - } - - // MARK: ExportSwift - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ wrappedValue: Float64) -> Wrapped? { let optionalRawValue = Double?.bridgeJSLiftParameter(isSome, wrappedValue) return optionalRawValue.flatMap { Wrapped(rawValue: $0) } } + @_spi(BridgeJS) public static func bridgeJSLiftReturnFromSideChannel() -> Wrapped? { + #if arch(wasm32) + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_double_presence") + func _swift_js_get_optional_double_presence() -> Int32 + @_extern(wasm, module: "bjs", name: "swift_js_get_optional_double_value") + func _swift_js_get_optional_double_value() -> Float64 + #else + func _swift_js_get_optional_double_presence() -> Int32 { + _onlyAvailableOnWasm() + } + func _swift_js_get_optional_double_value() -> Float64 { + _onlyAvailableOnWasm() + } + #endif + + let isSome = _swift_js_get_optional_double_presence() + if isSome == 0 { + return nil + } else { + let rawValue = _swift_js_get_optional_double_value() + return Wrapped(rawValue: Double(rawValue)) + } + } + @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { let optionalRawValue: Double? = self?.rawValue optionalRawValue.bridgeJSLowerReturn() @@ -1072,36 +1195,30 @@ extension Optional where Wrapped: _BridgedSwiftEnumNoPayload, Wrapped: RawRepres // MARK: Optional Associated Value Enum Support extension Optional where Wrapped: _BridgedSwiftAssociatedValueEnum { - // MARK: ImportTS + // MARK: ExportSwift - @_spi(BridgeJS) public consuming func bridgeJSLowerParameter() -> Int32 { + @_spi(BridgeJS) public consuming func bridgeJSLowerParameterWithPresence() -> (isSome: Int32, caseId: Int32) { switch consume self { case .none: - return -1 // Sentinel for nil + return (isSome: 0, caseId: 0) case .some(let value): - return value.bridgeJSLowerParameter() + return (isSome: 1, caseId: value.bridgeJSLowerParameter()) } } - @_spi(BridgeJS) public static func bridgeJSLiftReturn() -> Wrapped? { - // Read tag from side channel - let tag = _swift_js_pop_param_int32() - if tag == -1 { + @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ caseId: Int32) -> Wrapped? { + if isSome == 0 { return nil } else { - // Put tag back for the wrapped type's liftReturn to consume - _swift_js_push_int(tag) - return Wrapped.bridgeJSLiftReturn() + return Wrapped.bridgeJSLiftParameter(caseId) } } - // MARK: ExportSwift - - @_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32, _ caseId: Int32) -> Wrapped? { - if isSome == 0 { + @_spi(BridgeJS) public static func bridgeJSLiftReturn(_ caseId: Int32) -> Wrapped? { + if caseId == -1 { return nil } else { - return Wrapped.bridgeJSLiftParameter(caseId) + return Wrapped.bridgeJSLiftReturn(caseId) } } diff --git a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md index b6672a0a..4dba78c3 100644 --- a/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md +++ b/Sources/JavaScriptKit/Documentation.docc/Articles/BridgeJS/Exporting-Swift/Exporting-Swift-Protocols.md @@ -244,7 +244,4 @@ When you pass a JavaScript object implementing a protocol to Swift: | Protocol composition: `Protocol1 & Protocol2` | ❌ | | Generics | ❌ | -**Type Limitations:** -- `@JS enum` types are not supported in protocol signatures (use raw values or separate parameters instead) - -> Note: Protocol type support matches that of regular `@JS func` and `@JS class` exports. See and for more information. +> Note: Protocol type support matches that of regular `@JS func` and `@JS class` exports. See , , and for more information. diff --git a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift index 168a8c6e..97ebcfd2 100644 --- a/Tests/BridgeJSRuntimeTests/ExportAPITests.swift +++ b/Tests/BridgeJSRuntimeTests/ExportAPITests.swift @@ -863,7 +863,13 @@ enum APIOptionalResult { var count: Int { get set } var name: String { get } var optionalTag: String? { get set } + var optionalCount: Int? { get set } + var direction: Direction? { get set } + var optionalTheme: Theme? { get set } + var httpStatus: HttpStatus? { get set } var apiResult: APIResult? { get set } + var helper: Greeter { get set } + var optionalHelper: Greeter? { get set } func increment(by amount: Int) func getValue() -> Int func setLabelElements(_ labelPrefix: String, _ labelSuffix: String) @@ -873,8 +879,8 @@ enum APIOptionalResult { func createGreeter() -> Greeter func processOptionalGreeter(_ greeter: Greeter?) -> String func createOptionalGreeter() -> Greeter? - func handleAPIResult(_ result: APIResult) - func getAPIResult() -> APIResult + func handleAPIResult(_ result: APIResult?) + func getAPIResult() -> APIResult? } @JS class DataProcessorManager { @@ -919,13 +925,67 @@ enum APIOptionalResult { @JS func hasBackup() -> Bool { return backupProcessor != nil } + + @JS func getProcessorOptionalTag() -> String? { + return processor.optionalTag + } + + @JS func setProcessorOptionalTag(_ tag: String?) { + processor.optionalTag = tag + } + + @JS func getProcessorOptionalCount() -> Int? { + return processor.optionalCount + } + + @JS func setProcessorOptionalCount(_ count: Int?) { + processor.optionalCount = count + } + + @JS func getProcessorDirection() -> Direction? { + return processor.direction + } + + @JS func setProcessorDirection(_ direction: Direction?) { + processor.direction = direction + } + + @JS func getProcessorTheme() -> Theme? { + return processor.optionalTheme + } + + @JS func setProcessorTheme(_ theme: Theme?) { + processor.optionalTheme = theme + } + + @JS func getProcessorHttpStatus() -> HttpStatus? { + return processor.httpStatus + } + + @JS func setProcessorHttpStatus(_ status: HttpStatus?) { + processor.httpStatus = status + } + + @JS func getProcessorAPIResult() -> APIResult? { + return processor.getAPIResult() + } + + @JS func setProcessorAPIResult(_ apiResult: APIResult?) { + processor.handleAPIResult(apiResult) + } } @JS class SwiftDataProcessor: DataProcessor { @JS var count: Int = 0 @JS let name: String = "SwiftDataProcessor" @JS var optionalTag: String? = nil + @JS var optionalCount: Int? = nil + @JS var direction: Direction? = nil + @JS var optionalTheme: Theme? = nil + @JS var httpStatus: HttpStatus? = nil @JS var apiResult: APIResult? = nil + @JS var helper: Greeter = Greeter(name: "DefaultHelper") + @JS var optionalHelper: Greeter? = nil private var label: String = "" @JS init() {} @@ -970,12 +1030,12 @@ enum APIOptionalResult { return Greeter(name: "OptionalProcessorGreeter") } - @JS func handleAPIResult(_ result: APIResult) { + @JS func handleAPIResult(_ result: APIResult?) { self.apiResult = result } - @JS func getAPIResult() -> APIResult { - return apiResult ?? .failure(0) + @JS func getAPIResult() -> APIResult? { + return apiResult } } diff --git a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift index 58938a94..350ef7ae 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift +++ b/Tests/BridgeJSRuntimeTests/Generated/BridgeJS.ExportSwift.swift @@ -19,11 +19,7 @@ struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_getValue") func _extern_getValue(this: Int32) -> Int32 let ret = _extern_getValue(this: Int32(bitPattern: jsObject.id)) -<<<<<<< HEAD return Int.bridgeJSLiftReturn(ret) -======= - return Int.bridgeJSLiftReturn(ret) ->>>>>>> f19c8b06 (WIP: Initial protocol support) } func setLabelElements(_ labelPrefix: String, _ labelSuffix: String) { @@ -36,11 +32,7 @@ struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_getLabel") func _extern_getLabel(this: Int32) -> Int32 let ret = _extern_getLabel(this: Int32(bitPattern: jsObject.id)) -<<<<<<< HEAD return String.bridgeJSLiftReturn(ret) -======= - return String.bridgeJSLiftReturn(ret) ->>>>>>> f19c8b06 (WIP: Initial protocol support) } func isEven() -> Bool { @@ -66,8 +58,9 @@ struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { func processOptionalGreeter(_ greeter: Optional) -> String { @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_processOptionalGreeter") - func _extern_processOptionalGreeter(this: Int32, greeter: UnsafeMutableRawPointer) -> Int32 - let ret = _extern_processOptionalGreeter(this: Int32(bitPattern: jsObject.id), greeter: greeter.bridgeJSLowerParameter()) + func _extern_processOptionalGreeter(this: Int32, greeterIsSome: Int32, greeterPointer: UnsafeMutableRawPointer) -> Int32 + let (greeterIsSome, greeterPointer) = greeter.bridgeJSLowerParameterWithPresence() + let ret = _extern_processOptionalGreeter(this: Int32(bitPattern: jsObject.id), greeterIsSome: greeterIsSome, greeterPointer: greeterPointer) return String.bridgeJSLiftReturn(ret) } @@ -78,17 +71,18 @@ struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { return Optional.bridgeJSLiftReturn(ret) } - func handleAPIResult(_ result: APIResult) { + func handleAPIResult(_ result: Optional) { @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_handleAPIResult") - func _extern_handleAPIResult(this: Int32, result: Int32) - _extern_handleAPIResult(this: Int32(bitPattern: jsObject.id), result: result.bridgeJSLowerParameter()) + func _extern_handleAPIResult(this: Int32, resultIsSome: Int32, resultCaseId: Int32) + let (resultIsSome, resultCaseId) = result.bridgeJSLowerParameterWithPresence() + _extern_handleAPIResult(this: Int32(bitPattern: jsObject.id), resultIsSome: resultIsSome, resultCaseId: resultCaseId) } - func getAPIResult() -> APIResult { + func getAPIResult() -> Optional { @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_getAPIResult") - func _extern_getAPIResult(this: Int32) - _extern_getAPIResult(this: Int32(bitPattern: jsObject.id)) - return APIResult.bridgeJSLiftReturn() + func _extern_getAPIResult(this: Int32) -> Int32 + let ret = _extern_getAPIResult(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturn(ret) } var count: Int { @@ -117,28 +111,119 @@ struct AnyDataProcessor: DataProcessor, _BridgedSwiftProtocolWrapper { var optionalTag: Optional { get { @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalTag_get") + func _extern_get(this: Int32) + _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturnFromSideChannel() + } + set { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalTag_set") + func _extern_set(this: Int32, isSome: Int32, value: Int32) + let (isSome, value) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, value: value) + } + } + + var optionalCount: Optional { + get { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalCount_get") + func _extern_get(this: Int32) + _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturnFromSideChannel() + } + set { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalCount_set") + func _extern_set(this: Int32, isSome: Int32, value: Int32) + let (isSome, value) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, value: value) + } + } + + var direction: Optional { + get { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_direction_get") func _extern_get(this: Int32) -> Int32 let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) - return Optional.bridgeJSLiftReturn(ret) + return Optional.bridgeJSLiftReturn(ret) } set { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalTag_set") - func _extern_set(this: Int32, value: Int32) - _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_direction_set") + func _extern_set(this: Int32, isSome: Int32, value: Int32) + let (isSome, value) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, value: value) } } - var apiResult: Optional { + var optionalTheme: Optional { get { - @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_apiResult_get") + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalTheme_get") func _extern_get(this: Int32) _extern_get(this: Int32(bitPattern: jsObject.id)) - return Optional.bridgeJSLiftReturn() + return Optional.bridgeJSLiftReturnFromSideChannel() + } + set { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalTheme_set") + func _extern_set(this: Int32, isSome: Int32, value: Int32) + let (isSome, value) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, value: value) + } + } + + var httpStatus: Optional { + get { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_httpStatus_get") + func _extern_get(this: Int32) + _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturnFromSideChannel() + } + set { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_httpStatus_set") + func _extern_set(this: Int32, isSome: Int32, value: Int32) + let (isSome, value) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, value: value) + } + } + + var apiResult: Optional { + get { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_apiResult_get") + func _extern_get(this: Int32) -> Int32 + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturn(ret) } set { @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_apiResult_set") - func _extern_set(this: Int32, value: Int32) - _extern_set(this: Int32(bitPattern: jsObject.id), value: newValue.bridgeJSLowerParameter()) + func _extern_set(this: Int32, isSome: Int32, caseId: Int32) + let (isSome, caseId) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, caseId: caseId) + } + } + + var helper: Greeter { + get { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_helper_get") + func _extern_get(this: Int32) -> UnsafeMutableRawPointer + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Greeter.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_helper_set") + func _extern_set(this: Int32, pointer: UnsafeMutableRawPointer) + _extern_set(this: Int32(bitPattern: jsObject.id), pointer: newValue.bridgeJSLowerParameter()) + } + } + + var optionalHelper: Optional { + get { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalHelper_get") + func _extern_get(this: Int32) -> UnsafeMutableRawPointer + let ret = _extern_get(this: Int32(bitPattern: jsObject.id)) + return Optional.bridgeJSLiftReturn(ret) + } + set { + @_extern(wasm, module: "BridgeJSRuntimeTests", name: "bjs_DataProcessor_optionalHelper_set") + func _extern_set(this: Int32, isSome: Int32, pointer: UnsafeMutableRawPointer) + let (isSome, pointer) = newValue.bridgeJSLowerParameterWithPresence() + _extern_set(this: Int32(bitPattern: jsObject.id), isSome: isSome, pointer: pointer) } } @@ -412,8 +497,7 @@ extension APIResult: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> APIResult { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> APIResult { return _bridgeJSLiftFromCaseId(caseId) } @@ -534,8 +618,7 @@ extension ComplexResult: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> ComplexResult { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> ComplexResult { return _bridgeJSLiftFromCaseId(caseId) } @@ -649,8 +732,7 @@ extension Utilities.Result: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> Utilities.Result { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> Utilities.Result { return _bridgeJSLiftFromCaseId(caseId) } @@ -719,8 +801,7 @@ extension API.NetworkingResult: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> API.NetworkingResult { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> API.NetworkingResult { return _bridgeJSLiftFromCaseId(caseId) } @@ -812,8 +893,7 @@ extension APIOptionalResult: _BridgedSwiftAssociatedValueEnum { } } - @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn() -> APIOptionalResult { - let caseId = _swift_js_pop_param_int32() + @_spi(BridgeJS) @_transparent public static func bridgeJSLiftReturn(_ caseId: Int32) -> APIOptionalResult { return _bridgeJSLiftFromCaseId(caseId) } @@ -3723,6 +3803,132 @@ public func _bjs_DataProcessorManager_hasBackup(_self: UnsafeMutableRawPointer) #endif } +@_expose(wasm, "bjs_DataProcessorManager_getProcessorOptionalTag") +@_cdecl("bjs_DataProcessorManager_getProcessorOptionalTag") +public func _bjs_DataProcessorManager_getProcessorOptionalTag(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).getProcessorOptionalTag() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataProcessorManager_setProcessorOptionalTag") +@_cdecl("bjs_DataProcessorManager_setProcessorOptionalTag") +public func _bjs_DataProcessorManager_setProcessorOptionalTag(_self: UnsafeMutableRawPointer, tagIsSome: Int32, tagBytes: Int32, tagLength: Int32) -> Void { + #if arch(wasm32) + DataProcessorManager.bridgeJSLiftParameter(_self).setProcessorOptionalTag(_: Optional.bridgeJSLiftParameter(tagIsSome, tagBytes, tagLength)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataProcessorManager_getProcessorOptionalCount") +@_cdecl("bjs_DataProcessorManager_getProcessorOptionalCount") +public func _bjs_DataProcessorManager_getProcessorOptionalCount(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).getProcessorOptionalCount() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataProcessorManager_setProcessorOptionalCount") +@_cdecl("bjs_DataProcessorManager_setProcessorOptionalCount") +public func _bjs_DataProcessorManager_setProcessorOptionalCount(_self: UnsafeMutableRawPointer, countIsSome: Int32, countValue: Int32) -> Void { + #if arch(wasm32) + DataProcessorManager.bridgeJSLiftParameter(_self).setProcessorOptionalCount(_: Optional.bridgeJSLiftParameter(countIsSome, countValue)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataProcessorManager_getProcessorDirection") +@_cdecl("bjs_DataProcessorManager_getProcessorDirection") +public func _bjs_DataProcessorManager_getProcessorDirection(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).getProcessorDirection() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataProcessorManager_setProcessorDirection") +@_cdecl("bjs_DataProcessorManager_setProcessorDirection") +public func _bjs_DataProcessorManager_setProcessorDirection(_self: UnsafeMutableRawPointer, directionIsSome: Int32, directionValue: Int32) -> Void { + #if arch(wasm32) + DataProcessorManager.bridgeJSLiftParameter(_self).setProcessorDirection(_: Optional.bridgeJSLiftParameter(directionIsSome, directionValue)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataProcessorManager_getProcessorTheme") +@_cdecl("bjs_DataProcessorManager_getProcessorTheme") +public func _bjs_DataProcessorManager_getProcessorTheme(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).getProcessorTheme() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataProcessorManager_setProcessorTheme") +@_cdecl("bjs_DataProcessorManager_setProcessorTheme") +public func _bjs_DataProcessorManager_setProcessorTheme(_self: UnsafeMutableRawPointer, themeIsSome: Int32, themeBytes: Int32, themeLength: Int32) -> Void { + #if arch(wasm32) + DataProcessorManager.bridgeJSLiftParameter(_self).setProcessorTheme(_: Optional.bridgeJSLiftParameter(themeIsSome, themeBytes, themeLength)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataProcessorManager_getProcessorHttpStatus") +@_cdecl("bjs_DataProcessorManager_getProcessorHttpStatus") +public func _bjs_DataProcessorManager_getProcessorHttpStatus(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).getProcessorHttpStatus() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataProcessorManager_setProcessorHttpStatus") +@_cdecl("bjs_DataProcessorManager_setProcessorHttpStatus") +public func _bjs_DataProcessorManager_setProcessorHttpStatus(_self: UnsafeMutableRawPointer, statusIsSome: Int32, statusValue: Int32) -> Void { + #if arch(wasm32) + DataProcessorManager.bridgeJSLiftParameter(_self).setProcessorHttpStatus(_: Optional.bridgeJSLiftParameter(statusIsSome, statusValue)) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataProcessorManager_getProcessorAPIResult") +@_cdecl("bjs_DataProcessorManager_getProcessorAPIResult") +public func _bjs_DataProcessorManager_getProcessorAPIResult(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = DataProcessorManager.bridgeJSLiftParameter(_self).getProcessorAPIResult() + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_DataProcessorManager_setProcessorAPIResult") +@_cdecl("bjs_DataProcessorManager_setProcessorAPIResult") +public func _bjs_DataProcessorManager_setProcessorAPIResult(_self: UnsafeMutableRawPointer, apiResultIsSome: Int32, apiResultCaseId: Int32) -> Void { + #if arch(wasm32) + DataProcessorManager.bridgeJSLiftParameter(_self).setProcessorAPIResult(_: Optional.bridgeJSLiftParameter(apiResultIsSome, apiResultCaseId)) + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_DataProcessorManager_processor_get") @_cdecl("bjs_DataProcessorManager_processor_get") public func _bjs_DataProcessorManager_processor_get(_self: UnsafeMutableRawPointer) -> Int32 { @@ -3897,9 +4103,9 @@ public func _bjs_SwiftDataProcessor_createOptionalGreeter(_self: UnsafeMutableRa @_expose(wasm, "bjs_SwiftDataProcessor_handleAPIResult") @_cdecl("bjs_SwiftDataProcessor_handleAPIResult") -public func _bjs_SwiftDataProcessor_handleAPIResult(_self: UnsafeMutableRawPointer, result: Int32) -> Void { +public func _bjs_SwiftDataProcessor_handleAPIResult(_self: UnsafeMutableRawPointer, resultIsSome: Int32, resultCaseId: Int32) -> Void { #if arch(wasm32) - SwiftDataProcessor.bridgeJSLiftParameter(_self).handleAPIResult(_: APIResult.bridgeJSLiftParameter(result)) + SwiftDataProcessor.bridgeJSLiftParameter(_self).handleAPIResult(_: Optional.bridgeJSLiftParameter(resultIsSome, resultCaseId)) #else fatalError("Only available on WebAssembly") #endif @@ -3969,6 +4175,90 @@ public func _bjs_SwiftDataProcessor_optionalTag_set(_self: UnsafeMutableRawPoint #endif } +@_expose(wasm, "bjs_SwiftDataProcessor_optionalCount_get") +@_cdecl("bjs_SwiftDataProcessor_optionalCount_get") +public func _bjs_SwiftDataProcessor_optionalCount_get(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).optionalCount + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_optionalCount_set") +@_cdecl("bjs_SwiftDataProcessor_optionalCount_set") +public func _bjs_SwiftDataProcessor_optionalCount_set(_self: UnsafeMutableRawPointer, valueIsSome: Int32, valueValue: Int32) -> Void { + #if arch(wasm32) + SwiftDataProcessor.bridgeJSLiftParameter(_self).optionalCount = Optional.bridgeJSLiftParameter(valueIsSome, valueValue) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_direction_get") +@_cdecl("bjs_SwiftDataProcessor_direction_get") +public func _bjs_SwiftDataProcessor_direction_get(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).direction + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_direction_set") +@_cdecl("bjs_SwiftDataProcessor_direction_set") +public func _bjs_SwiftDataProcessor_direction_set(_self: UnsafeMutableRawPointer, valueIsSome: Int32, valueValue: Int32) -> Void { + #if arch(wasm32) + SwiftDataProcessor.bridgeJSLiftParameter(_self).direction = Optional.bridgeJSLiftParameter(valueIsSome, valueValue) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_optionalTheme_get") +@_cdecl("bjs_SwiftDataProcessor_optionalTheme_get") +public func _bjs_SwiftDataProcessor_optionalTheme_get(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).optionalTheme + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_optionalTheme_set") +@_cdecl("bjs_SwiftDataProcessor_optionalTheme_set") +public func _bjs_SwiftDataProcessor_optionalTheme_set(_self: UnsafeMutableRawPointer, valueIsSome: Int32, valueBytes: Int32, valueLength: Int32) -> Void { + #if arch(wasm32) + SwiftDataProcessor.bridgeJSLiftParameter(_self).optionalTheme = Optional.bridgeJSLiftParameter(valueIsSome, valueBytes, valueLength) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_httpStatus_get") +@_cdecl("bjs_SwiftDataProcessor_httpStatus_get") +public func _bjs_SwiftDataProcessor_httpStatus_get(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).httpStatus + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_httpStatus_set") +@_cdecl("bjs_SwiftDataProcessor_httpStatus_set") +public func _bjs_SwiftDataProcessor_httpStatus_set(_self: UnsafeMutableRawPointer, valueIsSome: Int32, valueValue: Int32) -> Void { + #if arch(wasm32) + SwiftDataProcessor.bridgeJSLiftParameter(_self).httpStatus = Optional.bridgeJSLiftParameter(valueIsSome, valueValue) + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_SwiftDataProcessor_apiResult_get") @_cdecl("bjs_SwiftDataProcessor_apiResult_get") public func _bjs_SwiftDataProcessor_apiResult_get(_self: UnsafeMutableRawPointer) -> Void { @@ -3990,6 +4280,48 @@ public func _bjs_SwiftDataProcessor_apiResult_set(_self: UnsafeMutableRawPointer #endif } +@_expose(wasm, "bjs_SwiftDataProcessor_helper_get") +@_cdecl("bjs_SwiftDataProcessor_helper_get") +public func _bjs_SwiftDataProcessor_helper_get(_self: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + #if arch(wasm32) + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).helper + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_helper_set") +@_cdecl("bjs_SwiftDataProcessor_helper_set") +public func _bjs_SwiftDataProcessor_helper_set(_self: UnsafeMutableRawPointer, value: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + SwiftDataProcessor.bridgeJSLiftParameter(_self).helper = Greeter.bridgeJSLiftParameter(value) + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_optionalHelper_get") +@_cdecl("bjs_SwiftDataProcessor_optionalHelper_get") +public func _bjs_SwiftDataProcessor_optionalHelper_get(_self: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + let ret = SwiftDataProcessor.bridgeJSLiftParameter(_self).optionalHelper + return ret.bridgeJSLowerReturn() + #else + fatalError("Only available on WebAssembly") + #endif +} + +@_expose(wasm, "bjs_SwiftDataProcessor_optionalHelper_set") +@_cdecl("bjs_SwiftDataProcessor_optionalHelper_set") +public func _bjs_SwiftDataProcessor_optionalHelper_set(_self: UnsafeMutableRawPointer, valueIsSome: Int32, valueValue: UnsafeMutableRawPointer) -> Void { + #if arch(wasm32) + SwiftDataProcessor.bridgeJSLiftParameter(_self).optionalHelper = Optional.bridgeJSLiftParameter(valueIsSome, valueValue) + #else + fatalError("Only available on WebAssembly") + #endif +} + @_expose(wasm, "bjs_SwiftDataProcessor_deinit") @_cdecl("bjs_SwiftDataProcessor_deinit") public func _bjs_SwiftDataProcessor_deinit(pointer: UnsafeMutableRawPointer) { diff --git a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json index cc380749..c0e0a4a8 100644 --- a/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json +++ b/Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.ExportSwift.json @@ -1346,6 +1346,310 @@ "returnType" : { "bool" : { + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_getProcessorOptionalTag", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getProcessorOptionalTag", + "parameters" : [ + + ], + "returnType" : { + "optional" : { + "_0" : { + "string" : { + + } + } + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_setProcessorOptionalTag", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setProcessorOptionalTag", + "parameters" : [ + { + "label" : "_", + "name" : "tag", + "type" : { + "optional" : { + "_0" : { + "string" : { + + } + } + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_getProcessorOptionalCount", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getProcessorOptionalCount", + "parameters" : [ + + ], + "returnType" : { + "optional" : { + "_0" : { + "int" : { + + } + } + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_setProcessorOptionalCount", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setProcessorOptionalCount", + "parameters" : [ + { + "label" : "_", + "name" : "count", + "type" : { + "optional" : { + "_0" : { + "int" : { + + } + } + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_getProcessorDirection", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getProcessorDirection", + "parameters" : [ + + ], + "returnType" : { + "optional" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_setProcessorDirection", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setProcessorDirection", + "parameters" : [ + { + "label" : "_", + "name" : "direction", + "type" : { + "optional" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_getProcessorTheme", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getProcessorTheme", + "parameters" : [ + + ], + "returnType" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_setProcessorTheme", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setProcessorTheme", + "parameters" : [ + { + "label" : "_", + "name" : "theme", + "type" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_getProcessorHttpStatus", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getProcessorHttpStatus", + "parameters" : [ + + ], + "returnType" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_setProcessorHttpStatus", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setProcessorHttpStatus", + "parameters" : [ + { + "label" : "_", + "name" : "status", + "type" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + } + } + } + ], + "returnType" : { + "void" : { + + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_getProcessorAPIResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "getProcessorAPIResult", + "parameters" : [ + + ], + "returnType" : { + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + } + }, + { + "abiName" : "bjs_DataProcessorManager_setProcessorAPIResult", + "effects" : { + "isAsync" : false, + "isStatic" : false, + "isThrows" : false + }, + "name" : "setProcessorAPIResult", + "parameters" : [ + { + "label" : "_", + "name" : "apiResult", + "type" : { + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } + } + } + } + ], + "returnType" : { + "void" : { + } } } @@ -1607,8 +1911,12 @@ "label" : "_", "name" : "result", "type" : { - "associatedValueEnum" : { - "_0" : "APIResult" + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } } } } @@ -1631,8 +1939,12 @@ ], "returnType" : { - "associatedValueEnum" : { - "_0" : "APIResult" + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } } } } @@ -1673,6 +1985,64 @@ } } }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "optionalCount", + "type" : { + "optional" : { + "_0" : { + "int" : { + + } + } + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "direction", + "type" : { + "optional" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "optionalTheme", + "type" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "httpStatus", + "type" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + } + } + }, { "isReadonly" : false, "isStatic" : false, @@ -1686,6 +2056,30 @@ } } } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "helper", + "type" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + }, + { + "isReadonly" : false, + "isStatic" : false, + "name" : "optionalHelper", + "type" : { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + } } ], "swiftCallName" : "SwiftDataProcessor" @@ -6181,8 +6575,12 @@ "label" : "_", "name" : "result", "type" : { - "associatedValueEnum" : { - "_0" : "APIResult" + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } } } } @@ -6205,8 +6603,12 @@ ], "returnType" : { - "associatedValueEnum" : { - "_0" : "APIResult" + "optional" : { + "_0" : { + "associatedValueEnum" : { + "_0" : "APIResult" + } + } } } } @@ -6244,6 +6646,60 @@ } } }, + { + "isReadonly" : false, + "name" : "optionalCount", + "type" : { + "optional" : { + "_0" : { + "int" : { + + } + } + } + } + }, + { + "isReadonly" : false, + "name" : "direction", + "type" : { + "optional" : { + "_0" : { + "caseEnum" : { + "_0" : "Direction" + } + } + } + } + }, + { + "isReadonly" : false, + "name" : "optionalTheme", + "type" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "Theme", + "_1" : "String" + } + } + } + } + }, + { + "isReadonly" : false, + "name" : "httpStatus", + "type" : { + "optional" : { + "_0" : { + "rawValueEnum" : { + "_0" : "HttpStatus", + "_1" : "Int" + } + } + } + } + }, { "isReadonly" : false, "name" : "apiResult", @@ -6256,6 +6712,28 @@ } } } + }, + { + "isReadonly" : false, + "name" : "helper", + "type" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + }, + { + "isReadonly" : false, + "name" : "optionalHelper", + "type" : { + "optional" : { + "_0" : { + "swiftHeapObject" : { + "_0" : "Greeter" + } + } + } + } } ] } diff --git a/Tests/prelude.mjs b/Tests/prelude.mjs index cb67a6a7..10c390af 100644 --- a/Tests/prelude.mjs +++ b/Tests/prelude.mjs @@ -811,12 +811,19 @@ function setupTestGlobals(global) { function testProtocolSupport(exports) { let processorValue = 0; let processorLabel = ""; - let apiResultValue = null; + let lastAPIResult = null; const jsProcessor = { count: 0, name: "JSProcessor", optionalTag: null, - apiResult: null, + direction: null, + optionalTheme: null, + httpStatus: null, + get apiResult() { return lastAPIResult; }, + set apiResult(value) { lastAPIResult = value; }, + helper: new exports.Greeter("JSHelper"), + optionalHelper: null, + optionalCount: null, increment(amount) { processorValue += amount; this.count += amount; }, getValue() { return processorValue; }, setLabelElements(labelPrefix, labelSuffix) { processorLabel = labelPrefix + labelSuffix; }, @@ -828,154 +835,213 @@ function testProtocolSupport(exports) { return greeter ? `JSProcessor processed optional: ${greeter.greet()}` : "JSProcessor received null"; }, createOptionalGreeter() { return new exports.Greeter("JSOptionalGreeter"); }, - handleAPIResult(result) { apiResultValue = result; }, - getAPIResult() { return apiResultValue; } + handleAPIResult(result) { lastAPIResult = result; }, + getAPIResult() { return lastAPIResult; } }; - const manager = new exports.DataProcessorManager(jsProcessor); - - assert.equal(jsProcessor.count, 0); - assert.equal(jsProcessor.name, "JSProcessor"); - - manager.incrementByAmount(4); - assert.equal(manager.getCurrentValue(), 4); + const successResult = { tag: exports.Result.Tag.Success, param0: "Operation completed" }; + const failureResult = { tag: exports.Result.Tag.Failure, param0: 500 }; + + const jsManager = new exports.DataProcessorManager(jsProcessor); + + jsManager.incrementByAmount(4); + assert.equal(jsManager.getCurrentValue(), 4); assert.equal(jsProcessor.count, 4); - manager.setProcessorLabel("Test", "Label"); - assert.equal(manager.getProcessorLabel(), "TestLabel"); - assert.equal(jsProcessor.getLabel(), "TestLabel"); + jsManager.setProcessorLabel("Test", "Label"); + assert.equal(jsManager.getProcessorLabel(), "TestLabel"); + + assert.equal(jsManager.isProcessorEven(), true); + jsManager.incrementByAmount(1); + assert.equal(jsManager.isProcessorEven(), false); + + assert.equal(jsManager.getProcessorOptionalTag(), null); + jsManager.setProcessorOptionalTag("test-tag"); + assert.equal(jsManager.getProcessorOptionalTag(), "test-tag"); + jsManager.setProcessorOptionalTag("another-tag"); + assert.equal(jsManager.getProcessorOptionalTag(), "another-tag"); + jsManager.setProcessorOptionalTag(null); + assert.equal(jsManager.getProcessorOptionalTag(), null); + + // Test direct property access for optionalTag + jsProcessor.optionalTag = "direct-tag"; + assert.equal(jsManager.getProcessorOptionalTag(), "direct-tag"); + assert.equal(jsProcessor.optionalTag, "direct-tag"); + jsProcessor.optionalTag = null; + assert.equal(jsManager.getProcessorOptionalTag(), null); + assert.equal(jsProcessor.optionalTag, null); - assert.equal(manager.isProcessorEven(), true); - manager.incrementByAmount(1); - assert.equal(manager.isProcessorEven(), false); - assert.equal(jsProcessor.isEven(), false); + assert.equal(jsManager.getProcessorDirection(), null); + jsManager.setProcessorDirection(exports.Direction.North); + assert.equal(jsManager.getProcessorDirection(), exports.Direction.North); + jsManager.setProcessorDirection(exports.Direction.East); + assert.equal(jsManager.getProcessorDirection(), exports.Direction.East); + jsManager.setProcessorDirection(null); + assert.equal(jsManager.getProcessorDirection(), null); + + assert.equal(jsManager.getProcessorTheme(), null); + jsManager.setProcessorTheme(exports.Theme.Light); + assert.equal(jsManager.getProcessorTheme(), exports.Theme.Light); + jsManager.setProcessorTheme(exports.Theme.Dark); + assert.equal(jsManager.getProcessorTheme(), exports.Theme.Dark); + jsManager.setProcessorTheme(null); + assert.equal(jsManager.getProcessorTheme(), null); + + assert.equal(jsManager.getProcessorHttpStatus(), null); + jsManager.setProcessorHttpStatus(exports.HttpStatus.Ok); + assert.equal(jsManager.getProcessorHttpStatus(), exports.HttpStatus.Ok); + jsManager.setProcessorHttpStatus(exports.HttpStatus.NotFound); + assert.equal(jsManager.getProcessorHttpStatus(), exports.HttpStatus.NotFound); + jsManager.setProcessorHttpStatus(null); + assert.equal(jsManager.getProcessorHttpStatus(), null); - jsProcessor.increment(3); - assert.equal(jsProcessor.getValue(), 8); - manager.release(); + jsProcessor.handleAPIResult(successResult); + assert.deepEqual(jsProcessor.getAPIResult(), successResult); + + jsProcessor.handleAPIResult(failureResult); + assert.deepEqual(jsProcessor.getAPIResult(), failureResult); + + jsProcessor.apiResult = successResult; + assert.deepEqual(jsProcessor.apiResult, successResult); + jsProcessor.apiResult = null; + assert.equal(jsProcessor.apiResult, null); + assert.equal(jsManager.getProcessorAPIResult(), null); + + assert.equal(jsProcessor.helper.name, "JSHelper"); + const newHelper = new exports.Greeter("UpdatedHelper"); + jsProcessor.helper = newHelper; + assert.equal(jsProcessor.helper.name, "UpdatedHelper"); + assert.equal(jsProcessor.helper.greet(), "Hello, UpdatedHelper!"); + + assert.equal(jsProcessor.optionalHelper, null); + const optHelper = new exports.Greeter("OptHelper"); + jsProcessor.optionalHelper = optHelper; + assert.equal(jsProcessor.optionalHelper.name, "OptHelper"); + assert.equal(jsProcessor.optionalHelper.greet(), "Hello, OptHelper!"); + jsProcessor.optionalHelper = null; + assert.equal(jsProcessor.optionalHelper, null); + + assert.equal(jsManager.getProcessorOptionalCount(), null); + jsManager.setProcessorOptionalCount(42); + assert.equal(jsManager.getProcessorOptionalCount(), 42); + jsManager.setProcessorOptionalCount(0); + assert.equal(jsManager.getProcessorOptionalCount(), 0); + jsManager.setProcessorOptionalCount(-100); + assert.equal(jsManager.getProcessorOptionalCount(), -100); + jsManager.setProcessorOptionalCount(null); + assert.equal(jsManager.getProcessorOptionalCount(), null); + + assert.equal(jsProcessor.optionalCount, null); + jsProcessor.optionalCount = 42; + assert.equal(jsProcessor.optionalCount, 42); + assert.equal(jsManager.getProcessorOptionalCount(), 42); + jsProcessor.optionalCount = 0; + assert.equal(jsProcessor.optionalCount, 0); + jsProcessor.optionalCount = null; + assert.equal(jsProcessor.optionalCount, null); + + newHelper.release(); + optHelper.release(); + jsManager.release(); const swiftProcessor = new exports.SwiftDataProcessor(); const swiftManager = new exports.DataProcessorManager(swiftProcessor); - assert.equal(swiftProcessor.count, 0); - assert.equal(swiftProcessor.name, "SwiftDataProcessor"); - swiftManager.incrementByAmount(10); assert.equal(swiftManager.getCurrentValue(), 10); - assert.equal(swiftProcessor.count, 10); swiftManager.setProcessorLabel("Swift", "Label"); assert.equal(swiftManager.getProcessorLabel(), "SwiftLabel"); - swiftProcessor.increment(5); - assert.equal(swiftProcessor.getValue(), 15); - assert.equal(swiftProcessor.count, 15); - - swiftProcessor.count = 100; - assert.equal(swiftProcessor.count, 100); - assert.equal(swiftProcessor.getValue(), 100); - - const testGreeter = new exports.Greeter("TestUser"); - const jsResult = jsProcessor.processGreeter(testGreeter); - assert.equal(jsResult, "JSProcessor processed: Hello, TestUser!"); - - const swiftResult = swiftProcessor.processGreeter(testGreeter); - assert.equal(swiftResult, "SwiftProcessor processed: Hello, TestUser!"); - - // Test swiftHeapObject return from protocol methods - const jsCreatedGreeter = jsProcessor.createGreeter(); - assert.equal(jsCreatedGreeter.name, "JSProcessorGreeter"); - assert.equal(jsCreatedGreeter.greet(), "Hello, JSProcessorGreeter!"); - jsCreatedGreeter.release(); - - const swiftCreatedGreeter = swiftProcessor.createGreeter(); - assert.equal(swiftCreatedGreeter.name, "ProcessorGreeter"); - assert.equal(swiftCreatedGreeter.greet(), "Hello, ProcessorGreeter!"); - swiftCreatedGreeter.release(); - - const optGreeterTest = new exports.Greeter("OptionalTest"); - assert.equal(jsProcessor.processOptionalGreeter(optGreeterTest), "JSProcessor processed optional: Hello, OptionalTest!"); - assert.equal(jsProcessor.processOptionalGreeter(null), "JSProcessor received null"); - assert.equal(swiftProcessor.processOptionalGreeter(optGreeterTest), "SwiftProcessor processed optional: Hello, OptionalTest!"); - assert.equal(swiftProcessor.processOptionalGreeter(null), "SwiftProcessor received nil"); - optGreeterTest.release(); - - const jsOptGreeter = jsProcessor.createOptionalGreeter(); - assert.notEqual(jsOptGreeter, null); - assert.equal(jsOptGreeter.name, "JSOptionalGreeter"); - jsOptGreeter.release(); - - const swiftOptGreeter = swiftProcessor.createOptionalGreeter(); - assert.notEqual(swiftOptGreeter, null); - assert.equal(swiftOptGreeter.name, "OptionalProcessorGreeter"); - swiftOptGreeter.release(); - - assert.equal(jsProcessor.optionalTag, null); - jsProcessor.optionalTag = "test-tag"; - assert.equal(jsProcessor.optionalTag, "test-tag"); - jsProcessor.optionalTag = null; - assert.equal(jsProcessor.optionalTag, null); - - const successResult = { tag: exports.Result.Tag.Success, param0: "Operation completed" }; - const failureResult = { tag: exports.Result.Tag.Failure, param0: 500 }; - - jsProcessor.handleAPIResult(successResult); - assert.deepEqual(jsProcessor.getAPIResult(), successResult); - - jsProcessor.handleAPIResult(failureResult); - assert.deepEqual(jsProcessor.getAPIResult(), failureResult); - - assert.equal(jsProcessor.apiResult, null); - jsProcessor.apiResult = successResult; - assert.deepEqual(jsProcessor.apiResult, successResult); - jsProcessor.apiResult = null; - assert.equal(jsProcessor.apiResult, null); - - testGreeter.release(); - + assert.equal(swiftManager.isProcessorEven(), true); + swiftManager.incrementByAmount(1); + assert.equal(swiftManager.isProcessorEven(), false); + + assert.equal(swiftManager.getProcessorDirection(), null); + swiftManager.setProcessorDirection(exports.Direction.South); + assert.equal(swiftManager.getProcessorDirection(), exports.Direction.South); + swiftManager.setProcessorDirection(exports.Direction.West); + assert.equal(swiftManager.getProcessorDirection(), exports.Direction.West); + swiftManager.setProcessorDirection(null); + assert.equal(swiftManager.getProcessorDirection(), null); + + assert.equal(swiftManager.getProcessorTheme(), null); + swiftProcessor.optionalTheme = exports.Theme.Light; + assert.equal(swiftManager.getProcessorTheme(), exports.Theme.Light); + swiftManager.setProcessorTheme(exports.Theme.Auto); + assert.equal(swiftManager.getProcessorTheme(), exports.Theme.Auto); + swiftManager.setProcessorTheme(exports.Theme.Light); + assert.equal(swiftManager.getProcessorTheme(), exports.Theme.Light); + swiftManager.setProcessorTheme(null); + assert.equal(swiftManager.getProcessorTheme(), null); + + assert.equal(swiftManager.getProcessorHttpStatus(), null); + swiftManager.setProcessorHttpStatus(exports.HttpStatus.ServerError); + assert.equal(swiftManager.getProcessorHttpStatus(), exports.HttpStatus.ServerError); + swiftManager.setProcessorHttpStatus(exports.HttpStatus.Ok); + assert.equal(swiftManager.getProcessorHttpStatus(), exports.HttpStatus.Ok); + swiftManager.setProcessorHttpStatus(null); + assert.equal(swiftManager.getProcessorHttpStatus(), null); + + swiftProcessor.handleAPIResult(successResult); + assert.deepEqual(swiftProcessor.getAPIResult(), successResult); + assert.deepEqual(swiftManager.getProcessorAPIResult(), successResult); + + swiftProcessor.handleAPIResult(failureResult); + assert.deepEqual(swiftProcessor.getAPIResult(), failureResult); + assert.deepEqual(swiftManager.getProcessorAPIResult(), failureResult); + swiftManager.setProcessorAPIResult(successResult); + assert.deepEqual(swiftProcessor.getAPIResult(), successResult); + swiftManager.release(); swiftProcessor.release(); - let optionalProcessorValue = 100; - let optionalProcessorLabel = "optional"; - const optionalProcessor = { + let backupValue = 100; + const backupProcessor = { count: 100, - name: "OptionalProcessor", - optionalTag: "optional-tag", + name: "BackupProcessor", + optionalTag: null, + direction: null, + optionalTheme: null, + httpStatus: null, apiResult: null, - increment(amount) { optionalProcessorValue += amount; this.count += amount; }, - getValue() { return optionalProcessorValue; }, - setLabelElements(labelPrefix, labelSuffix) { optionalProcessorLabel = labelPrefix + labelSuffix; }, - getLabel() { return optionalProcessorLabel; }, - isEven() { return optionalProcessorValue % 2 === 0; }, - processGreeter(greeter) { return `OptionalProcessor processed: ${greeter.greet()}`; }, - createGreeter() { return new exports.Greeter("OptionalProcessorGreeter"); }, - processOptionalGreeter(greeter) { - return greeter ? `OptionalProcessor processed optional: ${greeter.greet()}` : "OptionalProcessor received null"; - }, + helper: new exports.Greeter("BackupHelper"), + optionalHelper: null, + optionalCount: null, + increment(amount) { backupValue += amount; this.count += amount; }, + getValue() { return backupValue; }, + setLabelElements(labelPrefix, labelSuffix) { }, + getLabel() { return "backup"; }, + isEven() { return backupValue % 2 === 0; }, + processGreeter(greeter) { return ""; }, + createGreeter() { return new exports.Greeter("BackupGreeter"); }, + processOptionalGreeter(greeter) { return ""; }, createOptionalGreeter() { return null; }, handleAPIResult(result) { }, getAPIResult() { return { tag: exports.APIResult.Tag.Info }; } }; - let mainProcessorValue = 0; - let mainProcessorLabel = "main"; + let mainValue = 0; const mainProcessor = { count: 0, name: "MainProcessor", optionalTag: null, + direction: null, + optionalTheme: null, + httpStatus: null, apiResult: null, - increment(amount) { mainProcessorValue += amount; this.count += amount; }, - getValue() { return mainProcessorValue; }, - setLabelElements(labelPrefix, labelSuffix) { mainProcessorLabel = labelPrefix + labelSuffix; }, - getLabel() { return mainProcessorLabel; }, - isEven() { return mainProcessorValue % 2 === 0; }, - processGreeter(greeter) { return `MainProcessor processed: ${greeter.greet()}`; }, - createGreeter() { return new exports.Greeter("MainProcessorGreeter"); }, - processOptionalGreeter(greeter) { - return greeter ? `MainProcessor processed optional: ${greeter.greet()}` : "MainProcessor received null"; - }, - createOptionalGreeter() { return new exports.Greeter("MainOptionalGreeter"); }, + helper: new exports.Greeter("MainHelper"), + optionalHelper: null, + optionalCount: null, + increment(amount) { mainValue += amount; this.count += amount; }, + getValue() { return mainValue; }, + setLabelElements(labelPrefix, labelSuffix) { }, + getLabel() { return "main"; }, + isEven() { return mainValue % 2 === 0; }, + processGreeter(greeter) { return ""; }, + createGreeter() { return new exports.Greeter("MainGreeter"); }, + processOptionalGreeter(greeter) { return ""; }, + createOptionalGreeter() { return null; }, handleAPIResult(result) { }, getAPIResult() { return { tag: exports.APIResult.Tag.Info }; } }; @@ -986,7 +1052,7 @@ function testProtocolSupport(exports) { assert.equal(managerWithOptional.hasBackup(), false); assert.equal(managerWithOptional.getBackupValue(), null); - managerWithOptional.backupProcessor = optionalProcessor; + managerWithOptional.backupProcessor = backupProcessor; assert.notEqual(managerWithOptional.backupProcessor, null); assert.equal(managerWithOptional.hasBackup(), true); @@ -1006,15 +1072,16 @@ function testProtocolSupport(exports) { assert.equal(managerWithOptional.getCurrentValue(), 3); assert.equal(managerWithOptional.getBackupValue(), null); - const swiftBackupProcessor = new exports.SwiftDataProcessor(); - swiftBackupProcessor.increment(1); - managerWithOptional.backupProcessor = swiftBackupProcessor; + const swiftBackup = new exports.SwiftDataProcessor(); + managerWithOptional.backupProcessor = swiftBackup; assert.equal(managerWithOptional.hasBackup(), true); + assert.equal(managerWithOptional.getBackupValue(), 0); + + managerWithOptional.incrementBoth(); + assert.equal(managerWithOptional.getCurrentValue(), 4); assert.equal(managerWithOptional.getBackupValue(), 1); - assert.equal(swiftBackupProcessor.count, 1); - assert.equal(swiftBackupProcessor.name, "SwiftDataProcessor"); managerWithOptional.release(); - swiftBackupProcessor.release(); + swiftBackup.release(); } From eb1f0e3883af4ac86e239094809cec68572e3089 Mon Sep 17 00:00:00 2001 From: Krzysztof Rodak Date: Fri, 24 Oct 2025 10:03:41 +0200 Subject: [PATCH 6/6] BridgeJS: Update PackageToJS template and add short instruction --- CONTRIBUTING.md | 4 ++++ Plugins/PackageToJS/Templates/instantiate.js | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 666b62d2..9ca71ef1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -112,5 +112,9 @@ Run this script when you've made changes to: These changes require updating the pre-generated Swift bindings committed to the repository. +**Adding new BridgeJS intrinsics:** + +If you add new `@_extern(wasm, module: "bjs")` functions to [`BridgeJSInstrincics.swift`](Sources/JavaScriptKit/BridgeJSInstrincics.swift), also add corresponding stub entries to [`Plugins/PackageToJS/Templates/instantiate.js`](Plugins/PackageToJS/Templates/instantiate.js) in the `importObject["bjs"]` object. This allows packages without BridgeJS-generated code to instantiate successfully. + ## Support If you have any questions or need assistance, feel free to reach out via [GitHub Issues](https://github.com/swiftwasm/JavaScriptKit/issues) or [Discord](https://discord.gg/ashJW8T8yp). diff --git a/Plugins/PackageToJS/Templates/instantiate.js b/Plugins/PackageToJS/Templates/instantiate.js index 236b7020..5d74cc7e 100644 --- a/Plugins/PackageToJS/Templates/instantiate.js +++ b/Plugins/PackageToJS/Templates/instantiate.js @@ -54,6 +54,13 @@ async function createInstantiator(options, swift) { swift_js_return_optional_float: unexpectedBjsCall, swift_js_return_optional_heap_object: unexpectedBjsCall, swift_js_return_optional_object: unexpectedBjsCall, + swift_js_get_optional_int_presence: unexpectedBjsCall, + swift_js_get_optional_int_value: unexpectedBjsCall, + swift_js_get_optional_string: unexpectedBjsCall, + swift_js_get_optional_float_presence: unexpectedBjsCall, + swift_js_get_optional_float_value: unexpectedBjsCall, + swift_js_get_optional_double_presence: unexpectedBjsCall, + swift_js_get_optional_double_value: unexpectedBjsCall, } }, /** @param {WebAssembly.Instance} instance */