Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Embind pass lambda function as callback parameter

I would like to create a function, which calculates something. And after it's finished, it calls the callback function.

void calculate(int param1, ..., std::function<void(void)> callback) {
    //code...
    callback();
}

The binding of the function is created using Embind:

EMSCRIPTEN_BINDINGS(my_module) {
    function("calculate", &calculate);
}

But if I try to call Module.calculate(0, ..., function(){/*...*/}) I get this error:

UnboundTypeError: Cannot call calculate due to unbound types: NSt3__18functionIFvvEEE
like image 706
Iter Ator Avatar asked Mar 12 '23 17:03

Iter Ator


2 Answers

I'm not sure if it's the only way, but to pass callbacks from Js -> C++, I've had to

  • Not use std::function, but raw function pointers
  • Use Runtime.addFunction to get a C++ function pointer for a Javascript function, and pass that into the C++ world instead of trying to pass a Javascript function directly.
  • Not use EMBIND, but rather the cwrap/ccall API.

For your example, simplifying the interface slightly so only the callback is passed from JS -> C++, the C++ could look like the following:

extern "C" {

EMSCRIPTEN_KEEPALIVE
void calculate(void (*callback)()) {
  callback();
}

}

The Javascript to create the callback function pointer could look like

var callbackPointer = Module.Runtime.addFunction(function() {
  console.log('In the callback');
});

and to call the function, passing the pointer (as a "number"):

Module.ccall('calculate', 'number', ['number'], [callbackPointer]);

and then compiling making sure to reserve room for the function pointer:

em++ app.cpp -s RESERVED_FUNCTION_POINTERS=1 -o app.js
like image 190
Michal Charemza Avatar answered Mar 15 '23 06:03

Michal Charemza


You can now do it like this:

void calculate(int param1, ..., emscripten::val callback) {
    callback();
}

The EMSCRIPTEN_BINDINGS is unchanged.

The callback can even take parameters, provided they are of supported/declared types (e.g. if you pass an std::vector<blah> parameter to the callback, make sure you've used register_vector<blah>().)

like image 29
Malvineous Avatar answered Mar 15 '23 05:03

Malvineous