Seems this is not supported currently, but it's quite handy to have (for example callbacks). I tried implementing it, but I'm very new to both v8 and v8pp. Also not that good with template programming either. But here is something I got working, and maybe can be used to build somewhat better implementation.
template<typename T, typename ...Args>
struct V8CallFunc
{
V8CallFunc(v8::Isolate* isolate, v8::Local<v8::Function> func)
: isolate(isolate), func(isolate, func)
{
}
T operator()(Args&&... args) const
{
v8::EscapableHandleScope scope(isolate);
int const arg_count = sizeof...(Args);
// +1 to allocate array for arg_count == 0
v8::Local<v8::Value> v8_args[arg_count + 1] =
{
to_v8(isolate, std::forward<Args>(args))...
};
v8::TryCatch try_catch(isolate);
v8::Local<v8::Value> result;
v8::Local<v8::Function> funcLocal = func.Get(isolate);
bool const not_empty = funcLocal->Call(isolate->GetCurrentContext(), funcLocal, arg_count, v8_args).ToLocal(&result);
if (try_catch.HasCaught())
{
std::string const msg = v8pp::from_v8<std::string>(isolate,
try_catch.Exception()->ToString(isolate->GetCurrentContext()).ToLocalChecked());
THROW(std::runtime_error, msg);
}
assert(not_empty);
return from_v8<T>(isolate, scope.Escape(result));
}
v8::Isolate* isolate;
v8::Eternal<v8::Function> func;
};
template<typename ...Args>
struct V8CallFunc<void, Args...>
{
V8CallFunc(v8::Isolate* isolate, v8::Local<v8::Function> func)
: isolate(isolate), func(isolate, func)
{
}
void operator()(Args&&... args) const
{
v8::EscapableHandleScope scope(isolate);
int const arg_count = sizeof...(Args);
// +1 to allocate array for arg_count == 0
v8::Local<v8::Value> v8_args[arg_count + 1] =
{
to_v8(isolate, std::forward<Args>(args))...
};
v8::TryCatch try_catch(isolate);
v8::Local<v8::Function> funcLocal = func.Get(isolate);
funcLocal->Call(isolate->GetCurrentContext(), funcLocal, arg_count, v8_args);
if (try_catch.HasCaught())
{
std::string const msg = v8pp::from_v8<std::string>(isolate,
try_catch.Exception()->ToString(isolate->GetCurrentContext()).ToLocalChecked());
THROW(std::runtime_error, msg);
}
}
v8::Isolate* isolate;
v8::Eternal<v8::Function> func;
};
template <typename Ret, typename... Args> __forceinline
std::function<Ret(Args...)> createV8CallFunc(std::function<Ret(Args...)> f, v8::Isolate* isolate, v8::Local<v8::Function> func)
{
return V8CallFunc<Ret, Args...>(isolate, func);
}
template<typename T>
struct convert<std::function<T>>
{
using from_type = std::function<T>;
using to_type = v8::Local<v8::Function>;
static bool is_valid(v8::Isolate* isolate, v8::Local<v8::Value> value)
{
return !value.IsEmpty() && value->IsFunction();
}
static from_type from_v8(v8::Isolate* isolate, v8::Local<v8::Value> value)
{
if (!is_valid(isolate, value))
{
THROW(invalid_argument, isolate, value, "Function");
}
auto func = value.As<v8::Function>();
return createV8CallFunc(from_type(), isolate, func);
}
static to_type to_v8(v8::Isolate* isolate, const from_type& func)
{
using T_type = typename std::decay<from_type>::type;
T_type func_copy = func;
v8::Local<v8::Function> fn = v8::Function::New(isolate->GetCurrentContext(),
&detail::forward_function<raw_ptr_traits, T_type>,
detail::set_external_data(isolate, std::forward<T_type>(func_copy))).ToLocalChecked();
return fn;
}
};
Hello,
Seems this is not supported currently, but it's quite handy to have (for example callbacks). I tried implementing it, but I'm very new to both v8 and v8pp. Also not that good with template programming either. But here is something I got working, and maybe can be used to build somewhat better implementation.