Support calling callbacks from custom classes
WayneKeenan opened this issue · comments
Hi,
I have a used case where it would be useful to be able to call a user defined function from a JSCPP defined C++ class.
'C style' would be ok, as I expect std::function based approach would required a large amount of work.
Thanks
Wayne
The support you ask for is now added to the master branch.
Example:
JSCPP/src/includes/dummy_class_foo.ts
Lines 26 to 35 in 377be0f
Lines 1 to 20 in 377be0f
great, thank you!
HI,
I've been trying to use this, but I want to call the callback from within the typescript defined class.
Imagine that my class is receiving background events and I want to dispatch that to the users callback.
But I'm getting an error.
For example, only changing your example _callback
to just store a reference:
var _userCallback:FunctionPointerVariable;
const _callback = function (rt: CRuntime, _this: ObjectVariable, f: FunctionPointerVariable, v: IntVariable) {
_userCallback=f;
}
Then in another member function defined in the typescript class I try to call that stashed function ref, e.g.:
const invokeUserCallback = function () {
const v = rt.val(rt.normalPointerType(rt.intTypeLiteral), 321, false);
_userCallback.v.target.v.target(rt, null, v);
}
I get this error:
TypeError: undefined is not an object (evaluating 'value.t')
I tried a few ways, one was to modify the signature so the I did not need to construct a pointer to an int, but I get the same error.
Any help greatly appreciated.
Thanks, Wayne.
Sorry, the error above is not related. The issue I have is that when I setup a setTimeout
in the custom TypeScript
class to call the stashed call-back I see the TS function called (console output) but the user callback doesn't, I see no output to cout
.
You are missing two things in your setup:
rt.val
produces a Variable, which takes a type and a value in that type. In your case, you are making a pointer-to-int variable (int*). Then you should do it like this:
// The actual variable to point to. Note the third argument indicates if it is a "left"(non-constant) variable.
const variable = rt.val(rt.intTypeLiteral, 321, true);
// The value of the pointer, which points to the variable above.
const pVariableVal = rt.makeNormalPointerValue(variable);
// The variable representing the pointer, with appropriate type and value and "left" property.
const v = rt.val(rt.normalPointerType(rt.intTypeLiteral), pVariableVal, false);
- Every C++ procedure returns a generator instead of executing right away. Calling
_userCallback.v.target.v.target(rt, null, v)
only returns a generator and you need to manually evaluate the generator to run the underlying C++ code.
All in all, the code should look like this:
let _userCallback: FunctionPointerVariable;
const _callback = function* (rt: CRuntime, _this: ObjectVariable, f: FunctionPointerVariable, v: IntVariable) {
_userCallback = f;
const r = yield* f.v.target.v.target(rt, null, v);
return r;
}
rt.regFunc(_callback, type, "callback", [
rt.functionPointerType(rt.intTypeLiteral, [
rt.normalPointerType(rt.intTypeLiteral)
]),
rt.normalPointerType(rt.intTypeLiteral)
], rt.intTypeLiteral);
// This is how you run a user-defined C++ procedure outside the interpretation loop.
setTimeout(() => {
const gen = (function*() {
const variable = rt.val(rt.intTypeLiteral, 321, true);
const pVariableVal = rt.makeNormalPointerValue(variable);
const v = rt.val(rt.normalPointerType(rt.intTypeLiteral), pVariableVal, false);
const r = yield* _userCallback.v.target.v.target(rt, null, v);
console.log(JSON.stringify(r));
})();
for (let v = gen.next(); !v.done; v = gen.next(v.value));
}, 1000);
That's great, thank you!