Search code examples
v8

storing a function that was retrieved from FunctionCallbackInfo


I'm pretty much trying to make a AddInputEvent but, after a month, can't find a way to turn a local "function from FunctionCallbackInfo"(i'll just call this argf) in to a Persistent Function so that garbage collection doesn't erase the pointers.

Most stakeoverflow threads and example code I can find just say to Cast argf with a Local Function; then to throw that in to a Persistent New. This results in a error: cannot convert 'v8::Local<v8::Function>' to 'v8::Function*'

here is the code, not completely sure why I can't convert it

class inputevnt_feld{
public:
    char* call_on;
    v8::Persistent<v8::Function> func;
};

int entvcount = -1;
vector<inputevnt_feld> event_calls; //this is pretty much a array of events that we can call later

// in js looks like this "AddInputEvent("string", function);"
void AddInputEvent( const v8::FunctionCallbackInfo<v8::Value>& args ) {
    v8::HandleScope handle_scope(args.GetIsolate());

    //gotta make sure that we ain't letting in some trojan horse that has nothing in it
    if (args[1]->IsFunction() && args[0]->IsString()) {
        inputevnt_feld newt;

        //converts js string to char array
        v8::String::Utf8Value str(args.GetIsolate(), args[0]);
        const char* cstr = ToCString(str);
        newt.call_on = (char*)cstr;

        //here is where the problem is with function casting
        v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(args[1]);
        newt.func = v8::Persistent<v8::Function>::New(args.GetIsolate(), callback);

        //push the new stuff in to even array
        event_calls.push_back(newt);

        //getting vector array size is too much for my smol brain
        //so I'ma just do this myself
        entvcount++;
        //cout << event_calls[entvcount].call_on << endl; //debug
    }

}

Solution

  • Most stakeoverflow threads and example code I can find just say to Cast argf with a Local Function; then to throw that in to a Persistent New

    Yes, that's correct. If you know how to read it, the C++ type system is your friend for figuring out the details.

    If you look at the definition of v8::PersistentBase<T>::New, you'll see that it takes a T* (for its template type T). If you look at the v8::Local<T> class, you'll see that a way to get a T* from it is to use its operator*. That leads to:

    v8::Local<v8::Function> callback = ...Cast(args[1]);
    ... = v8::Persistent<v8::Function>::New(..., *callback);
    

    Alternatively, you can use the Persistent constructor directly, and pass it the Local without dereferencing it first:

    v8::Local<v8::Function> callback = ...Cast(args[1]);
    ... = v8::Persistent<v8::Function>(..., callback);
    

    Both options are entirely equivalent. Personally I'd prefer the latter as it takes slightly fewer characters to spell out, but that's really the only difference.

    (Your current code as posted does something else: it ignores the result of the cast and passes the original args[1] directly to Persistent::New -- that's not going to work.)