Skip to content

BridgeJS: Standardize lift/lower pattern across Swift and JavaScript #423

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 24, 2025
8 changes: 2 additions & 6 deletions Benchmarks/Sources/Generated/BridgeJS.ImportTS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func benchmarkHelperNoopWithNumber(_ n: Double) throws(JSException) -> Void {
fatalError("Only available on WebAssembly")
}
#endif
bjs_benchmarkHelperNoopWithNumber(n)
bjs_benchmarkHelperNoopWithNumber(n.bridgeJSLowerParameter())
if let error = _swift_js_take_exception() {
throw error
}
Expand All @@ -45,11 +45,7 @@ func benchmarkRunner(_ name: String, _ body: JSObject) throws(JSException) -> Vo
fatalError("Only available on WebAssembly")
}
#endif
var name = name
let nameId = name.withUTF8 { b in
_swift_js_make_js_string(b.baseAddress.unsafelyUnwrapped, Int32(b.count))
}
bjs_benchmarkRunner(nameId, Int32(bitPattern: body.id))
bjs_benchmarkRunner(name.bridgeJSLowerParameter(), body.bridgeJSLowerParameter())
if let error = _swift_js_take_exception() {
throw error
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,19 @@
public func _bjs_PlayBridgeJS_init() -> UnsafeMutableRawPointer {
#if arch(wasm32)
let ret = PlayBridgeJS()
return Unmanaged.passRetained(ret).toOpaque()
return ret.bridgeJSLowerReturn()
#else
fatalError("Only available on WebAssembly")
#endif
}

@_expose(wasm, "bjs_PlayBridgeJS_update")
@_cdecl("bjs_PlayBridgeJS_update")
public func _bjs_PlayBridgeJS_update(_self: UnsafeMutableRawPointer, swiftSourceBytes: Int32, swiftSourceLen: Int32, dtsSourceBytes: Int32, dtsSourceLen: Int32) -> UnsafeMutableRawPointer {
public func _bjs_PlayBridgeJS_update(_self: UnsafeMutableRawPointer, swiftSourceBytes: Int32, swiftSourceLength: Int32, dtsSourceBytes: Int32, dtsSourceLength: Int32) -> UnsafeMutableRawPointer {
#if arch(wasm32)
do {
let swiftSource = String(unsafeUninitializedCapacity: Int(swiftSourceLen)) { b in
_swift_js_init_memory(swiftSourceBytes, b.baseAddress.unsafelyUnwrapped)
return Int(swiftSourceLen)
}
let dtsSource = String(unsafeUninitializedCapacity: Int(dtsSourceLen)) { b in
_swift_js_init_memory(dtsSourceBytes, b.baseAddress.unsafelyUnwrapped)
return Int(dtsSourceLen)
}
let ret = try Unmanaged<PlayBridgeJS>.fromOpaque(_self).takeUnretainedValue().update(swiftSource: swiftSource, dtsSource: dtsSource)
return Unmanaged.passRetained(ret).toOpaque()
let ret = try PlayBridgeJS.bridgeJSLiftParameter(_self).update(swiftSource: String.bridgeJSLiftParameter(swiftSourceBytes, swiftSourceLength), dtsSource: String.bridgeJSLiftParameter(dtsSourceBytes, dtsSourceLength))
return ret.bridgeJSLowerReturn()
} catch let error {
if let error = error.thrownValue.object {
withExtendedLifetime(error) {
Expand All @@ -56,10 +48,16 @@ public func _bjs_PlayBridgeJS_deinit(pointer: UnsafeMutableRawPointer) {
Unmanaged<PlayBridgeJS>.fromOpaque(pointer).release()
}

extension PlayBridgeJS: ConvertibleToJSValue {
extension PlayBridgeJS: ConvertibleToJSValue, _BridgedSwiftHeapObject {
var jsValue: JSValue {
#if arch(wasm32)
@_extern(wasm, module: "PlayBridgeJS", name: "bjs_PlayBridgeJS_wrap")
func _bjs_PlayBridgeJS_wrap(_: UnsafeMutableRawPointer) -> Int32
#else
func _bjs_PlayBridgeJS_wrap(_: UnsafeMutableRawPointer) -> Int32 {
fatalError("Only available on WebAssembly")
}
#endif
return .object(JSObject(id: UInt32(bitPattern: _bjs_PlayBridgeJS_wrap(Unmanaged.passRetained(self).toOpaque()))))
}
}
Expand All @@ -68,10 +66,8 @@ extension PlayBridgeJS: ConvertibleToJSValue {
@_cdecl("bjs_PlayBridgeJSOutput_outputJs")
public func _bjs_PlayBridgeJSOutput_outputJs(_self: UnsafeMutableRawPointer) -> Void {
#if arch(wasm32)
var ret = Unmanaged<PlayBridgeJSOutput>.fromOpaque(_self).takeUnretainedValue().outputJs()
return ret.withUTF8 { ptr in
_swift_js_return_string(ptr.baseAddress, Int32(ptr.count))
}
let ret = PlayBridgeJSOutput.bridgeJSLiftParameter(_self).outputJs()
return ret.bridgeJSLowerReturn()
#else
fatalError("Only available on WebAssembly")
#endif
Expand All @@ -81,10 +77,8 @@ public func _bjs_PlayBridgeJSOutput_outputJs(_self: UnsafeMutableRawPointer) ->
@_cdecl("bjs_PlayBridgeJSOutput_outputDts")
public func _bjs_PlayBridgeJSOutput_outputDts(_self: UnsafeMutableRawPointer) -> Void {
#if arch(wasm32)
var ret = Unmanaged<PlayBridgeJSOutput>.fromOpaque(_self).takeUnretainedValue().outputDts()
return ret.withUTF8 { ptr in
_swift_js_return_string(ptr.baseAddress, Int32(ptr.count))
}
let ret = PlayBridgeJSOutput.bridgeJSLiftParameter(_self).outputDts()
return ret.bridgeJSLowerReturn()
#else
fatalError("Only available on WebAssembly")
#endif
Expand All @@ -94,10 +88,8 @@ public func _bjs_PlayBridgeJSOutput_outputDts(_self: UnsafeMutableRawPointer) ->
@_cdecl("bjs_PlayBridgeJSOutput_importSwiftGlue")
public func _bjs_PlayBridgeJSOutput_importSwiftGlue(_self: UnsafeMutableRawPointer) -> Void {
#if arch(wasm32)
var ret = Unmanaged<PlayBridgeJSOutput>.fromOpaque(_self).takeUnretainedValue().importSwiftGlue()
return ret.withUTF8 { ptr in
_swift_js_return_string(ptr.baseAddress, Int32(ptr.count))
}
let ret = PlayBridgeJSOutput.bridgeJSLiftParameter(_self).importSwiftGlue()
return ret.bridgeJSLowerReturn()
#else
fatalError("Only available on WebAssembly")
#endif
Expand All @@ -107,10 +99,8 @@ public func _bjs_PlayBridgeJSOutput_importSwiftGlue(_self: UnsafeMutableRawPoint
@_cdecl("bjs_PlayBridgeJSOutput_exportSwiftGlue")
public func _bjs_PlayBridgeJSOutput_exportSwiftGlue(_self: UnsafeMutableRawPointer) -> Void {
#if arch(wasm32)
var ret = Unmanaged<PlayBridgeJSOutput>.fromOpaque(_self).takeUnretainedValue().exportSwiftGlue()
return ret.withUTF8 { ptr in
_swift_js_return_string(ptr.baseAddress, Int32(ptr.count))
}
let ret = PlayBridgeJSOutput.bridgeJSLiftParameter(_self).exportSwiftGlue()
return ret.bridgeJSLowerReturn()
#else
fatalError("Only available on WebAssembly")
#endif
Expand All @@ -122,10 +112,16 @@ public func _bjs_PlayBridgeJSOutput_deinit(pointer: UnsafeMutableRawPointer) {
Unmanaged<PlayBridgeJSOutput>.fromOpaque(pointer).release()
}

extension PlayBridgeJSOutput: ConvertibleToJSValue {
extension PlayBridgeJSOutput: ConvertibleToJSValue, _BridgedSwiftHeapObject {
var jsValue: JSValue {
#if arch(wasm32)
@_extern(wasm, module: "PlayBridgeJS", name: "bjs_PlayBridgeJSOutput_wrap")
func _bjs_PlayBridgeJSOutput_wrap(_: UnsafeMutableRawPointer) -> Int32
#else
func _bjs_PlayBridgeJSOutput_wrap(_: UnsafeMutableRawPointer) -> Int32 {
fatalError("Only available on WebAssembly")
}
#endif
return .object(JSObject(id: UInt32(bitPattern: _bjs_PlayBridgeJSOutput_wrap(Unmanaged.passRetained(self).toOpaque()))))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,14 @@ func createTS2Skeleton() throws(JSException) -> TS2Skeleton {
if let error = _swift_js_take_exception() {
throw error
}
return TS2Skeleton(takingThis: ret)
return TS2Skeleton.bridgeJSLiftReturn(ret)
}

struct TS2Skeleton {
let this: JSObject
struct TS2Skeleton: _JSBridgedClass {
let jsObject: JSObject

init(this: JSObject) {
self.this = this
}

init(takingThis this: Int32) {
self.this = JSObject(id: UInt32(bitPattern: this))
init(unsafelyWrapping jsObject: JSObject) {
self.jsObject = jsObject
}

func convert(_ ts: String) throws(JSException) -> String {
Expand All @@ -42,18 +38,11 @@ struct TS2Skeleton {
fatalError("Only available on WebAssembly")
}
#endif
var ts = ts
let tsId = ts.withUTF8 { b in
_swift_js_make_js_string(b.baseAddress.unsafelyUnwrapped, Int32(b.count))
}
let ret = bjs_TS2Skeleton_convert(Int32(bitPattern: self.this.id), tsId)
let ret = bjs_TS2Skeleton_convert(self.bridgeJSLowerParameter(), ts.bridgeJSLowerParameter())
if let error = _swift_js_take_exception() {
throw error
}
return String(unsafeUninitializedCapacity: Int(ret)) { b in
_swift_js_init_memory_with_result(b.baseAddress.unsafelyUnwrapped, Int32(ret))
return Int(ret)
}
return String.bridgeJSLiftReturn(ret)
}

}
7 changes: 6 additions & 1 deletion Plugins/BridgeJS/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,22 @@ let package = Package(
name: "BridgeJSCore",
dependencies: [
"BridgeJSSkeleton",
"BridgeJSUtilities",
.product(name: "SwiftParser", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftBasicFormat", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
]
),
.target(name: "BridgeJSSkeleton"),
.target(name: "BridgeJSUtilities"),

.target(
name: "BridgeJSLink",
dependencies: ["BridgeJSSkeleton"]
dependencies: [
"BridgeJSSkeleton",
"BridgeJSUtilities",
]
),

.testTarget(
Expand Down
Loading