Skip to content
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

Export function returning a JSValue #149

Closed
AndrewBarba opened this issue Jan 6, 2022 · 2 comments
Closed

Export function returning a JSValue #149

AndrewBarba opened this issue Jan 6, 2022 · 2 comments

Comments

@AndrewBarba
Copy link

AndrewBarba commented Jan 6, 2022

I've followed the basic docs to call an exported function that takes in string/numbers and returns string/numbers but I'm struggling to figure out how to get the JS runtime to await a returned JSPromise from the Swift runtime.

I started with this approach of returning a pointer to the JSPromise:

@_cdecl("fetch")
func fetch() -> UnsafeRawPointer {
    let promise = JSPromise { resolve in
        resolve(.success(5))
    }
    var value = promise.jsValue()
    return withUnsafePointer(to: &value) { UnsafeRawPointer($0) }
}

But it's obviously not so clear how to deserialize this to an actual Promise in JS:

async function jsFetch() {
  let ptr = instance.exports.fetch()
  let promise = /** ??? */
  await promise
}

I'm very new to WASM so I apologize if this is a completely wrong approach, I just needed to get the ball rolling because I can't find anything else online about returning more complex values. I've been trying to understand how its accomplished in Rust but they have fancy annotations from the wasm-bindgen crate which is frankly over my head.

@j-f1
Copy link
Member

j-f1 commented Jan 8, 2022

I think the best approach here would be to have the Swift side define a global value (by using JSObject.global.myLibrary = JSObject.global.Object.create(JSValue.null), for example), then defining properties such as fetch on that (using JSClosure). Then, from the JS side, you’d be able to pull the myLibrary value off of the global after initializing the SwiftWasm instance and call the fetch method.

@AndrewBarba
Copy link
Author

I'm stunned... this works perfectly. Can even await the promise off the global scope.

Here's where I ended up:

@_cdecl("fetch")
func fetch() -> Int {
    let globalKey = Int.random(in: Int.min...Int.max)
    let promise = JSPromise { resolve in
        resolve(.success(5))
    }
    JSObject.global["\(globalKey)"] = promise.jsValue()
    return globalKey
}

And then calling in JS:

const key = instance.exports.fetch()
const result = await global[key]
console.log('swift#fetch():', result)

Obviously need to manage cleaning up the global scope but this is an awesome start. Feel free to close this as needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants