Skip to content

Commit ee19ac2

Browse files
Fix optional dictionary bridging and add JSValue dictionary support
1 parent 47e7e2a commit ee19ac2

File tree

6 files changed

+149
-0
lines changed

6 files changed

+149
-0
lines changed

Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,23 @@ struct IntrinsicJSFragment: Sendable {
968968
printer.write("\(resultVar) = \(absenceLiteral);")
969969
}
970970
printer.write("}")
971+
case .dictionary(let valueType):
972+
let isSomeVar = scope.variable("isSome")
973+
printer.write("const \(isSomeVar) = \(JSGlueVariableScope.reservedTmpRetInts).pop();")
974+
printer.write("let \(resultVar);")
975+
printer.write("if (\(isSomeVar)) {")
976+
printer.indent {
977+
let dictLiftFragment = try! dictionaryLift(valueType: valueType)
978+
let liftResults = dictLiftFragment.printCode([], scope, printer, cleanupCode)
979+
if let liftResult = liftResults.first {
980+
printer.write("\(resultVar) = \(liftResult);")
981+
}
982+
}
983+
printer.write("} else {")
984+
printer.indent {
985+
printer.write("\(resultVar) = \(absenceLiteral);")
986+
}
987+
printer.write("}")
971988
case .jsValue:
972989
let isSomeVar = scope.variable("isSome")
973990
printer.write("const \(isSomeVar) = \(JSGlueVariableScope.reservedTmpRetInts).pop();")

Sources/JavaScriptKit/BridgeJSIntrinsics.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,6 +2399,27 @@ extension Optional where Wrapped: _BridgedSwiftDictionaryStackType {
23992399
}
24002400
}
24012401

2402+
@_spi(BridgeJS) public consuming func bridgeJSLowerReturn() {
2403+
switch consume self {
2404+
case .none:
2405+
_swift_js_push_i32(0)
2406+
case .some(let dict):
2407+
dict.bridgeJSLowerReturn()
2408+
_swift_js_push_i32(1)
2409+
}
2410+
}
2411+
2412+
@_spi(BridgeJS) public static func bridgeJSLiftParameter(_ isSome: Int32) -> [String: Wrapped.DictionaryValue]? {
2413+
if isSome == 0 {
2414+
return nil
2415+
}
2416+
return Dictionary<String, Wrapped.DictionaryValue>.bridgeJSLiftParameter()
2417+
}
2418+
2419+
@_spi(BridgeJS) public static func bridgeJSLiftParameter() -> [String: Wrapped.DictionaryValue]? {
2420+
bridgeJSLiftParameter(_swift_js_pop_i32())
2421+
}
2422+
24022423
@_spi(BridgeJS) public static func bridgeJSLiftReturn() -> [String: Wrapped.DictionaryValue]? {
24032424
let isSome = _swift_js_pop_i32()
24042425
if isSome == 0 {

Tests/BridgeJSRuntimeTests/ExportAPITests.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ func runJsWorks() -> Void
5252
return v
5353
}
5454

55+
@JS func roundTripDictionaryExport(v: [String: Int]) -> [String: Int] {
56+
return v
57+
}
58+
59+
@JS func roundTripOptionalDictionaryExport(v: [String: String]?) -> [String: String]? {
60+
return v
61+
}
62+
5563
@JS func roundTripJSValue(v: JSValue) -> JSValue {
5664
return v
5765
}

Tests/BridgeJSRuntimeTests/Generated/BridgeJS.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3810,6 +3810,28 @@ public func _bjs_roundTripJSObject(_ v: Int32) -> Int32 {
38103810
#endif
38113811
}
38123812

3813+
@_expose(wasm, "bjs_roundTripDictionaryExport")
3814+
@_cdecl("bjs_roundTripDictionaryExport")
3815+
public func _bjs_roundTripDictionaryExport() -> Void {
3816+
#if arch(wasm32)
3817+
let ret = roundTripDictionaryExport(v: [String: Int].bridgeJSLiftParameter())
3818+
return ret.bridgeJSLowerReturn()
3819+
#else
3820+
fatalError("Only available on WebAssembly")
3821+
#endif
3822+
}
3823+
3824+
@_expose(wasm, "bjs_roundTripOptionalDictionaryExport")
3825+
@_cdecl("bjs_roundTripOptionalDictionaryExport")
3826+
public func _bjs_roundTripOptionalDictionaryExport(_ v: Int32) -> Void {
3827+
#if arch(wasm32)
3828+
let ret = roundTripOptionalDictionaryExport(v: Optional<[String: String]>.bridgeJSLiftParameter(v))
3829+
return ret.bridgeJSLowerReturn()
3830+
#else
3831+
fatalError("Only available on WebAssembly")
3832+
#endif
3833+
}
3834+
38133835
@_expose(wasm, "bjs_roundTripJSValue")
38143836
@_cdecl("bjs_roundTripJSValue")
38153837
public func _bjs_roundTripJSValue(_ vKind: Int32, _ vPayload1: Int32, _ vPayload2: Float64) -> Void {

Tests/BridgeJSRuntimeTests/Generated/JavaScript/BridgeJS.json

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5577,6 +5577,82 @@
55775577
}
55785578
}
55795579
},
5580+
{
5581+
"abiName" : "bjs_roundTripDictionaryExport",
5582+
"effects" : {
5583+
"isAsync" : false,
5584+
"isStatic" : false,
5585+
"isThrows" : false
5586+
},
5587+
"name" : "roundTripDictionaryExport",
5588+
"parameters" : [
5589+
{
5590+
"label" : "v",
5591+
"name" : "v",
5592+
"type" : {
5593+
"dictionary" : {
5594+
"_0" : {
5595+
"int" : {
5596+
5597+
}
5598+
}
5599+
}
5600+
}
5601+
}
5602+
],
5603+
"returnType" : {
5604+
"dictionary" : {
5605+
"_0" : {
5606+
"int" : {
5607+
5608+
}
5609+
}
5610+
}
5611+
}
5612+
},
5613+
{
5614+
"abiName" : "bjs_roundTripOptionalDictionaryExport",
5615+
"effects" : {
5616+
"isAsync" : false,
5617+
"isStatic" : false,
5618+
"isThrows" : false
5619+
},
5620+
"name" : "roundTripOptionalDictionaryExport",
5621+
"parameters" : [
5622+
{
5623+
"label" : "v",
5624+
"name" : "v",
5625+
"type" : {
5626+
"nullable" : {
5627+
"_0" : {
5628+
"dictionary" : {
5629+
"_0" : {
5630+
"string" : {
5631+
5632+
}
5633+
}
5634+
}
5635+
},
5636+
"_1" : "null"
5637+
}
5638+
}
5639+
}
5640+
],
5641+
"returnType" : {
5642+
"nullable" : {
5643+
"_0" : {
5644+
"dictionary" : {
5645+
"_0" : {
5646+
"string" : {
5647+
5648+
}
5649+
}
5650+
}
5651+
},
5652+
"_1" : "null"
5653+
}
5654+
}
5655+
},
55805656
{
55815657
"abiName" : "bjs_roundTripJSValue",
55825658
"effects" : {

Tests/prelude.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,11 @@ function BridgeJSRuntimeTests_runJsWorks(instance, exports) {
291291
]) {
292292
assert.equal(exports.roundTripString(v), v);
293293
}
294+
const dict = { a: 1, b: 2 };
295+
assert.deepEqual(exports.roundTripDictionaryExport(dict), dict);
296+
const optDict = { hello: "world" };
297+
assert.deepEqual(exports.roundTripOptionalDictionaryExport(optDict), optDict);
298+
assert.equal(exports.roundTripOptionalDictionaryExport(null), null);
294299
const arrayStruct = { ints: [1, 2, 3], optStrings: ["a", "b"] };
295300
const arrayStructRoundTrip = exports.roundTripArrayMembers(arrayStruct);
296301
assert.deepEqual(arrayStructRoundTrip.ints, [1, 2, 3]);

0 commit comments

Comments
 (0)