18 #ifndef INCLUDED_FUNCTIONWRAPPER 19 #define INCLUDED_FUNCTIONWRAPPER 27 #include <type_traits> 56 std::is_same_v<const ScriptRequest&, T> || std::is_same_v<const ScriptInterface&, T>,
58 std::remove_const_t<typename std::remove_reference_t<T>>
68 template<
typename R,
typename ...Types>
71 static constexpr
const size_t nb_args =
sizeof...(Types);
74 using arg_types = std::tuple<type_transform<Types>...>;
77 template<
typename C,
typename R,
typename ...Types>
79 template<
typename C,
typename R,
typename ...Types>
91 template<
size_t idx,
typename T>
95 if constexpr (std::is_same_v<T, JS::HandleValue>)
99 if (idx >= args.length())
100 return std::forward_as_tuple(JS::UndefinedHandleValue);
105 return std::forward_as_tuple(args[idx]);
112 if (idx >= args.length())
113 return std::forward_as_tuple(T{});
117 went_ok &= Script::FromJSVal<T>(rq, args[idx], ret);
118 return std::forward_as_tuple(ret);
126 template<
size_t idx,
typename T,
typename V,
typename ...Types>
129 return std::tuple_cat(DoConvertFromJS<idx, T>(rq, args, went_ok), DoConvertFromJS<idx + 1, V, Types...>(rq, args, went_ok));
141 template<
typename ...Types>
144 if constexpr (
sizeof...(Types) == 0)
155 template<
typename ...Types>
156 static std::tuple<
const ScriptRequest&, Types...>
ConvertFromJS(
const ScriptRequest& rq, JS::CallArgs& args,
bool& went_ok, std::tuple<const ScriptRequest&, Types...>*)
158 if constexpr (
sizeof...(Types) == 0)
162 return std::forward_as_tuple(rq);
165 return std::tuple_cat(std::forward_as_tuple(rq), DoConvertFromJS<0, Types...>(rq, args, went_ok));
169 template<
typename ...Types>
170 static std::tuple<
const ScriptInterface&, Types...>
ConvertFromJS(
const ScriptRequest& rq, JS::CallArgs& args,
bool& went_ok, std::tuple<const ScriptInterface&, Types...>*)
172 if constexpr (
sizeof...(Types) == 0)
179 return std::tuple_cat(std::forward_as_tuple(rq.
GetScriptInterface()), DoConvertFromJS<0, Types...>(rq, args, went_ok));
188 template <auto callable,
typename T,
typename tuple>
191 if constexpr(std::is_same_v<T, void>)
195 return std::apply(callable, args);
198 return std::apply(callable, std::tuple_cat(std::forward_as_tuple(*
object), args));
210 template<
int i,
typename T,
typename... Ts>
211 static void AssignOrToJSValHelper(
const ScriptRequest& rq, JS::MutableHandleValueVector argv,
const T& a,
const Ts&... params)
214 AssignOrToJSValHelper<i+1>(rq, argv, params...);
217 template<
int i,
typename... Ts>
220 static_assert(
sizeof...(Ts) == 0);
230 template<
typename R,
typename ...Args>
231 static bool Call_(
const ScriptRequest& rq, JS::HandleValue val,
const char* name, R& ret,
const Args&... args)
233 JS::RootedObject obj(rq.
cx);
234 if (!JS_ValueToObject(rq.
cx, val, &obj) || !obj)
240 if (!JS_HasProperty(rq.
cx, obj, name, &found) || !found)
243 JS::RootedValueVector argv(rq.
cx);
245 AssignOrToJSValHelper<0>(rq, &argv, args...);
248 if constexpr (std::is_same_v<R, JS::MutableHandleValue>)
249 success = JS_CallFunctionName(rq.cx, obj, name, argv, ret);
252 JS::RootedValue jsRet(rq.cx);
253 success = JS_CallFunctionName(rq.cx, obj, name, argv, &jsRet);
254 if constexpr (!std::is_same_v<R, IgnoreResult_t>)
269 template <
typename T>
274 template <
class callableType>
290 template <auto callable, GetterFor<decltype(callable)> thisGetter =
nullptr>
295 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
296 ScriptRequest rq(cx);
299 static_assert(std::is_same_v<
typename args_info<decltype(callable)>::object_type,
void> || thisGetter !=
nullptr,
300 "ScriptFunction::Register - No getter specified for object method");
304 #pragma GCC diagnostic push 305 #pragma GCC diagnostic ignored "-Waddress" 307 ObjType* obj =
nullptr;
308 if constexpr (thisGetter !=
nullptr)
310 obj = thisGetter(rq, args);
315 #pragma GCC diagnostic pop 329 if constexpr (std::is_same_v<
void,
typename args_info<decltype(callable)>::return_type>)
330 call<callable>(obj, outs);
331 else if constexpr (std::is_same_v<
JS::Value,
typename args_info<decltype(callable)>::return_type>)
332 args.rval().set(call<callable>(obj, outs));
344 template<
typename R,
typename ...Args>
345 static bool Call(
const ScriptRequest& rq, JS::HandleValue val,
const char* name, R& ret,
const Args&... args)
347 return Call_(rq, val, name, ret, std::forward<const Args>(args)...);
351 template<
typename ...Args>
352 static bool Call(
const ScriptRequest& rq, JS::HandleValue val,
const char* name, JS::MutableHandleValue ret,
const Args&... args)
354 return Call_(rq, val, name, ret, std::forward<const Args>(args)...);
361 template<
typename ...Args>
362 static bool CallVoid(
const ScriptRequest& rq, JS::HandleValue val,
const char* name,
const Args&... args)
364 return Call(rq, val, name, IgnoreResult, std::forward<const Args>(args)...);
370 template <auto callable, GetterFor<decltype(callable)> thisGetter =
nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
371 static JSFunctionSpec
Wrap(
const char* name)
373 return JS_FN(name, (&ToJSNative<callable, thisGetter>),
args_info<decltype(callable)>::nb_args, flags);
379 template <auto callable, GetterFor<decltype(callable)> thisGetter =
nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
380 static JSFunction*
Create(
const ScriptRequest& rq,
const char* name)
382 return JS_NewFunction(rq.
cx, &ToJSNative<callable, thisGetter>,
args_info<decltype(callable)>::nb_args, flags, name);
388 template <auto callable, GetterFor<decltype(callable)> thisGetter =
nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
389 static void Register(
const ScriptRequest& rq,
const char* name)
391 JS_DefineFunction(rq.
cx, rq.
nativeScope, name, &ToJSNative<callable, thisGetter>,
args_info<decltype(callable)>::nb_args, flags);
399 template <auto callable, GetterFor<decltype(callable)> thisGetter =
nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
400 static void Register(JSContext* cx, JS::HandleObject scope,
const char* name)
402 JS_DefineFunction(cx, scope, name, &ToJSNative<callable, thisGetter>,
args_info<decltype(callable)>::nb_args, flags);
406 #endif // INCLUDED_FUNCTIONWRAPPER JSContext * cx
Definition: ScriptRequest.h:92
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
Definition: code_annotation.h:38
static bool Call(const ScriptRequest &rq, JS::HandleValue val, const char *name, R &ret, const Args &... args)
Call a JS function name, property of object val, with the arguments args.
Definition: FunctionWrapper.h:345
static std::tuple< T, V, Types... > DoConvertFromJS(const ScriptRequest &rq, JS::CallArgs &args, bool &went_ok)
Recursive wrapper: calls DoConvertFromJS for type T and recurses.
Definition: FunctionWrapper.h:127
static void AssignOrToJSValHelper(const ScriptRequest &rq, JS::MutableHandleValueVector argv, const T &a, const Ts &... params)
Recursive helper to call AssignOrToJSVal.
Definition: FunctionWrapper.h:211
static void Register(const ScriptRequest &rq, const char *name)
Register a function on the native scope (usually 'Engine').
Definition: FunctionWrapper.h:389
R return_type
Definition: FunctionWrapper.h:72
static std::tuple< const ScriptInterface &, Types... > ConvertFromJS(const ScriptRequest &rq, JS::CallArgs &args, bool &went_ok, std::tuple< const ScriptInterface &, Types... > *)
Definition: FunctionWrapper.h:170
static IgnoreResult_t IgnoreResult
Definition: FunctionWrapper.h:205
static void AssignOrToJSValHelper(const ScriptRequest &rq, JS::MutableHandleValueVector argv)
Definition: FunctionWrapper.h:218
static args_info< decltype(callable)>::return_type call(T *object, tuple &args)
Wrap std::apply for the case where we have an object method or a regular function.
Definition: FunctionWrapper.h:189
static std::tuple< Types... > ConvertFromJS(const ScriptRequest &rq, JS::CallArgs &args, bool &went_ok, std::tuple< Types... > *)
ConvertFromJS is a wrapper around DoConvertFromJS, and serves to:
Definition: FunctionWrapper.h:142
void ignore_result(const T &)
Silence the 'unused result' warning.
Definition: code_annotation.h:65
#define UNUSED2(param)
mark a function local variable or parameter as unused and avoid the corresponding compiler warning...
Definition: code_annotation.h:56
Convenient struct to get info on a [class] [const] function pointer.
Definition: FunctionWrapper.h:66
Config::Value_type Value
Definition: json_spirit_value.h:182
static bool ToJSNative(JSContext *cx, unsigned argc, JS::Value *vp)
The meat of this file.
Definition: FunctionWrapper.h:291
void ToJSVal(const ScriptRequest &rq, JS::MutableHandleValue ret, T const &val)
Convert a C++ type to a JS::Value.
std::tuple< type_transform< Types >... > arg_types
Definition: FunctionWrapper.h:74
#define T(string_literal)
Definition: secure_crt.cpp:77
void object_type
Definition: FunctionWrapper.h:73
static std::tuple< T > DoConvertFromJS(const ScriptRequest &rq, JS::CallArgs &args, bool &went_ok)
DoConvertFromJS takes a type, a JS argument, and converts.
Definition: FunctionWrapper.h:92
static JSFunction * Create(const ScriptRequest &rq, const char *name)
Return a JSFunction from a C++ function.
Definition: FunctionWrapper.h:380
bool IsPending(const ScriptRequest &rq)
Definition: ScriptExceptions.cpp:28
static JSFunctionSpec Wrap(const char *name)
Return a function spec from a C++ function.
Definition: FunctionWrapper.h:371
const ScriptInterface & GetScriptInterface() const
Return the scriptInterface active when creating this ScriptRequest.
Definition: ScriptInterface.cpp:97
JS::HandleObject nativeScope
Definition: ScriptRequest.h:94
Definition: FunctionWrapper.h:204
static bool CallVoid(const ScriptRequest &rq, JS::HandleValue val, const char *name, const Args &... args)
Call a JS function name, property of object val, with the arguments args.
Definition: FunctionWrapper.h:362
Abstraction around a SpiderMonkey JS::Realm.
Definition: ScriptInterface.h:71
This class introduces templates to conveniently wrap C++ functions in JSNative functions.
Definition: FunctionWrapper.h:39
T *(*)(const ScriptRequest &, JS::CallArgs &) ObjectGetter
Definition: FunctionWrapper.h:270
static std::tuple< const ScriptRequest &, Types... > ConvertFromJS(const ScriptRequest &rq, JS::CallArgs &args, bool &went_ok, std::tuple< const ScriptRequest &, Types... > *)
Definition: FunctionWrapper.h:156
bool CatchPending(const ScriptRequest &rq)
Log and then clear the current pending exception.
Definition: ScriptExceptions.cpp:33
ObjectGetter< typename args_info< callableType >::object_type > GetterFor
Definition: FunctionWrapper.h:275
Spidermonkey maintains some 'local' state via the JSContext* object.
Definition: ScriptRequest.h:59
std::conditional_t< std::is_same_v< const ScriptRequest &, T >||std::is_same_v< const ScriptInterface &, T >, T, std::remove_const_t< typename std::remove_reference_t< T > > > type_transform
In JS->C++ calls, types are converted using FromJSVal, and this requires them to be default-construct...
Definition: FunctionWrapper.h:59
static void Register(JSContext *cx, JS::HandleObject scope, const char *name)
Register a function on.
Definition: FunctionWrapper.h:400
static bool Call_(const ScriptRequest &rq, JS::HandleValue val, const char *name, R &ret, const Args &... args)
Wrapper around calling a JS function from C++.
Definition: FunctionWrapper.h:231
static bool Call(const ScriptRequest &rq, JS::HandleValue val, const char *name, JS::MutableHandleValue ret, const Args &... args)
Definition: FunctionWrapper.h:352
bool FromJSVal(const ScriptRequest &rq, const JS::HandleValue val, T &ret)
Convert a JS::Value to a C++ type.