I’ve figured this out, but I want to make sure what I have learnt is findable for the next person.
I couldn’t find any direct examples in the documentation, so ended up going off code that I found in github issues…
extern fn onReady(cb: fn ()callconv(.C) void) void;
fn cb () callconv(.C) void {
onReady(cb2);
}
fn cb2 () callconv(.C) void { }
export fn init () void {
onReady(cb);
}
init passes cb
to onReady(cb)
and then when cb
is called it passes cb2
to onReady(cb2)
note that onReady is defined with a function type, but not a function pointer, as you would do so in C.
using a function pointer does actually work but then on the javascript side onReady will get a memory address of value the function table entry, but this way it just gets the value.
for completeness, this is the javascript to load the wasm
const fs = require('fs');
const source = fs.readFileSync("./cb_c.wasm");
const typedArray = new Uint8Array(source);
var memory
;(async function () {
var callback
var buffer = Buffer.alloc(0)
var result = await WebAssembly.instantiate(typedArray, {
env: {
onReady: function (fn_ptr) {
var table = result.instance.exports.__indirect_function_table
var memory = Buffer.from(result.instance.exports.memory.buffer)
console.log('fn_ptr', fn_ptr)
callback = result.instance.exports.__indirect_function_table.get(fn_ptr)
//if you defined as a function pointer, this would be necessary:
//callback = result.instance.exports.__indirect_function_table.get(memory.readUInt32LE(fn_ptr))
},
}})
result.instance.exports.init()
callback()
}())
and here is the equivalent c
typedef void (*callback)();
void onReady (callback* cb);
void cb2 () { }
void cb () {
onReady(&cb2);
}
void init () {
onReady(&cb);
}