18#ifndef INCLUDED_FUNCTIONWRAPPER 
   19#define INCLUDED_FUNCTIONWRAPPER 
   25#include <fmt/format.h> 
   59        std::is_same_v<const ScriptRequest&, T> || std::is_same_v<const ScriptInterface&, T>,
 
   61        std::remove_const_t<typename std::remove_reference_t<T>>
 
   71    template<
typename R, 
typename ...Types>
 
   74        static constexpr const size_t nb_args = 
sizeof...(Types);
 
   77        using arg_types = std::tuple<type_transform<Types>...>;
 
   80    template<
typename C, 
typename R, 
typename ...Types>
 
   82    template<
typename C, 
typename R, 
typename ...Types>
 
   91            std::runtime_error{fmt::format(
"Failed to get `{}` from an `IteratorResult`.", property)}
 
   93        using std::runtime_error::runtime_error;
 
  105    template<
size_t idx, 
typename T>
 
  109        if constexpr (std::is_same_v<T, JS::HandleValue>)
 
  113            if (idx >= args.length())
 
  114                return JS::UndefinedHandleValue;
 
  126            if (idx >= args.length())
 
  131                wentOk &= Script::FromJSVal<T>(rq, args[idx], ret);
 
  140    template<
typename... 
T, 
size_t... idx>
 
  142        JS::CallArgs& args, 
bool& wentOk)
 
  144        return {DoConvertFromJS<idx, T>(rq, args, wentOk)...};
 
  155    template<
typename ...Types>
 
  157        std::tuple<Types...>*)
 
  159        return DoConvertFromJS<Types...>(std::index_sequence_for<Types...>(), rq, args, wentOk);
 
  163    template<
typename ...Types>
 
  165        JS::CallArgs& args, 
bool& wentOk, std::tuple<const ScriptRequest&, Types...>*)
 
  167        return std::tuple_cat(std::tie(rq), DoConvertFromJS<Types...>(
 
  168            std::index_sequence_for<Types...>(), rq, args, wentOk));
 
  172    template<
typename ...Types>
 
  174        JS::CallArgs& args, 
bool& wentOk, std::tuple<const ScriptInterface&, Types...>*)
 
  177            DoConvertFromJS<Types...>(std::index_sequence_for<Types...>(), rq, args, wentOk));
 
  186    template <auto callable, 
typename T, 
typename tuple>
 
  187    static typename args_info<
decltype(callable)>::return_type 
call(
T* 
object, tuple& args)
 
  189        if constexpr(std::is_same_v<T, void>)
 
  193            return std::apply(callable, args);
 
  196            return std::apply(callable, std::tuple_cat(std::forward_as_tuple(*
object), args));
 
  212    template<
typename... Types, 
size_t... idx>
 
  214        [[maybe_unused]] JS::MutableHandleValueVector argv, 
const Types&... params)
 
  225    template<
typename R, 
typename ...Args>
 
  226    static bool Call_(
const ScriptRequest& rq, JS::HandleValue val, 
const char* name, R& ret, 
const Args&... args)
 
  228        JS::RootedObject obj(rq.
cx);
 
  229        if (!JS_ValueToObject(rq.
cx, val, &obj) || !obj)
 
  233        JS::RootedValue func(rq.
cx);
 
  234        if (!JS_GetProperty(rq.
cx, obj, name, &func) || func.isUndefined())
 
  237        JS::RootedValueVector argv(rq.
cx);
 
  239        ToJSValVector(std::index_sequence_for<Args...>{}, rq, &argv, args...);
 
  242        if constexpr (std::is_same_v<R, JS::MutableHandleValue>)
 
  243            success = JS_CallFunctionValue(rq.
cx, obj, func, argv, ret);
 
  246            JS::RootedValue jsRet(rq.
cx);
 
  247            success = JS_CallFunctionValue(rq.
cx, obj, func, argv, &jsRet);
 
  248            if constexpr (!std::is_same_v<R, IgnoreResult_t>)
 
  263    template <
typename T>
 
  268    template <
class callableType>
 
  284    template <auto callable, GetterFor<decltype(callable)> thisGetter = 
nullptr>
 
  285    static bool ToJSNative(JSContext* cx, 
unsigned argc, JS::Value* vp)
 
  287        using ObjType = 
typename args_info<
decltype(callable)>::object_type;
 
  289        JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
 
  293        static_assert(std::is_same_v<
typename args_info<
decltype(callable)>::object_type, 
void> || thisGetter != 
nullptr,
 
  294                      "ScriptFunction::Register - No getter specified for object method");
 
  298#pragma GCC diagnostic push 
  299#pragma GCC diagnostic ignored "-Waddress" 
  301        ObjType* obj = 
nullptr;
 
  302        if constexpr (thisGetter != 
nullptr)
 
  304            obj = thisGetter(rq, args);
 
  309#pragma GCC diagnostic pop 
  314            static_cast<typename 
args_info<decltype(callable)
>::arg_types*>(
nullptr));
 
  324        if constexpr (std::is_same_v<void, 
typename args_info<
decltype(callable)>::return_type>)
 
  325            call<callable>(obj, outs);
 
  326        else if constexpr (std::is_same_v<JS::Value, 
typename args_info<
decltype(callable)>::return_type>)
 
  327            args.rval().set(call<callable>(obj, outs));
 
  339    template<
typename R, 
typename ...Args>
 
  340    static bool Call(
const ScriptRequest& rq, JS::HandleValue val, 
const char* name, R& ret, 
const Args&... args)
 
  342        return Call_(rq, val, name, ret, std::forward<const Args>(args)...);
 
  346    template<
typename ...Args>
 
  347    static bool Call(
const ScriptRequest& rq, JS::HandleValue val, 
const char* name, JS::MutableHandleValue ret, 
const Args&... args)
 
  349        return Call_(rq, val, name, ret, std::forward<const Args>(args)...);
 
  356    template<
typename ...Args>
 
  359        return Call(rq, val, name, 
IgnoreResult, std::forward<const Args>(args)...);
 
  367    template<
typename Callback>
 
  369        JS::HandleValue arg, Callback yieldCallback)
 
  371        JS::RootedValue generator{rq.
cx};
 
  373            throw std::runtime_error{fmt::format(
"Failed to call the generator `{}`.", name)};
 
  375        const auto continueGenerator = [&](
const char* property, 
auto... args) -> JS::Value
 
  377                JS::RootedValue iteratorResult{rq.
cx};
 
  379                    throw std::runtime_error{fmt::format(
"Failed to call `{}`.", name)};
 
  380                return iteratorResult;
 
  383        JS::PersistentRootedValue 
error{rq.
cx, JS::UndefinedValue()};
 
  386            JS::RootedValue iteratorResult{rq.
cx, 
error.isUndefined() ? continueGenerator(
"next") :
 
  387                continueGenerator(
"throw", std::exchange(
error, JS::UndefinedValue()))};
 
  391                JS::RootedObject iteratorResultObject{rq.
cx, &iteratorResult.toObject()};
 
  397                JS::RootedValue value{rq.
cx};
 
  398                if (!JS_GetProperty(rq.
cx, iteratorResultObject, 
"value", &value))
 
  404                yieldCallback(value);
 
  406            catch (
const std::exception& e)
 
  410                    throw std::runtime_error{
"Failed to construct `Error`."};
 
  418    template <auto callable, GetterFor<decltype(callable)> thisGetter = 
nullptr>
 
  419    static JSFunctionSpec 
Wrap(
const char* name,
 
  420        const u16 flags = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
 
  422        return JS_FN(name, (&ToJSNative<callable, thisGetter>), 
args_info<
decltype(callable)>::nb_args, flags);
 
  428    template <auto callable, GetterFor<decltype(callable)> thisGetter = 
nullptr>
 
  430        const u16 flags = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
 
  432        return JS_NewFunction(rq.
cx, &ToJSNative<callable, thisGetter>, 
args_info<
decltype(callable)>::nb_args, flags, name);
 
  438    template <auto callable, GetterFor<decltype(callable)> thisGetter = 
nullptr>
 
  440        const u16 flags = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
 
  442        JS_DefineFunction(rq.
cx, rq.
nativeScope, name, &ToJSNative<callable, thisGetter>, 
args_info<
decltype(callable)>::nb_args, flags);
 
  450    template <auto callable, GetterFor<decltype(callable)> thisGetter = 
nullptr>
 
  451    static void Register(JSContext* cx, JS::HandleObject scope, 
const char* name,
 
  452        const u16 flags = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)
 
  454        JS_DefineFunction(cx, scope, name, &ToJSNative<callable, thisGetter>, 
args_info<
decltype(callable)>::nb_args, flags);
 
This class introduces templates to conveniently wrap C++ functions in JSNative functions.
Definition: FunctionWrapper.h:42
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:357
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:226
ScriptFunction(const ScriptFunction &)=delete
static JSFunctionSpec Wrap(const char *name, const u16 flags=JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
Return a function spec from a C++ function.
Definition: FunctionWrapper.h:419
static bool Call(const ScriptRequest &rq, JS::HandleValue val, const char *name, JS::MutableHandleValue ret, const Args &... args)
Definition: FunctionWrapper.h:347
static JS::Value RunGenerator(const ScriptRequest &rq, JS::HandleValue val, const char *name, JS::HandleValue arg, Callback yieldCallback)
Call a JS function name, property of object val, with the argument args.
Definition: FunctionWrapper.h:368
static void Register(const ScriptRequest &rq, const char *name, const u16 flags=JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
Register a function on the native scope (usually 'Engine').
Definition: FunctionWrapper.h:439
static std::tuple< T... > DoConvertFromJS(std::index_sequence< idx... >, const ScriptRequest &rq, JS::CallArgs &args, bool &wentOk)
Wrapper: calls DoConvertFromJS for each element in T.
Definition: FunctionWrapper.h:141
static JSFunction * Create(const ScriptRequest &rq, const char *name, const u16 flags=JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
Return a JSFunction from a C++ function.
Definition: FunctionWrapper.h:429
static IgnoreResult_t IgnoreResult
Definition: FunctionWrapper.h:203
static void ToJSValVector(std::index_sequence< idx... >, const ScriptRequest &rq, JS::MutableHandleValueVector argv, const Types &... params)
Converts any number of arguments to a JS::MutableHandleValueVector.
Definition: FunctionWrapper.h:213
ObjectGetter< typename args_info< callableType >::object_type > GetterFor
Definition: FunctionWrapper.h:269
static std::tuple< Types... > ConvertFromJS(const ScriptRequest &rq, JS::CallArgs &args, bool &wentOk, std::tuple< Types... > *)
ConvertFromJS is a wrapper around DoConvertFromJS, and handles specific cases for the first argument ...
Definition: FunctionWrapper.h:156
static T DoConvertFromJS(const ScriptRequest &rq, JS::CallArgs &args, bool &wentOk)
DoConvertFromJS takes a type, a JS argument, and converts.
Definition: FunctionWrapper.h:106
static std::tuple< const ScriptInterface &, Types... > ConvertFromJS(const ScriptRequest &rq, JS::CallArgs &args, bool &wentOk, std::tuple< const ScriptInterface &, Types... > *)
Definition: FunctionWrapper.h:173
static bool ToJSNative(JSContext *cx, unsigned argc, JS::Value *vp)
The meat of this file.
Definition: FunctionWrapper.h:285
static void Register(JSContext *cx, JS::HandleObject scope, const char *name, const u16 flags=JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT)
Register a function on.
Definition: FunctionWrapper.h:451
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:187
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:62
ScriptFunction(ScriptFunction &&)=delete
static std::tuple< const ScriptRequest &, Types... > ConvertFromJS(const ScriptRequest &rq, JS::CallArgs &args, bool &wentOk, std::tuple< const ScriptRequest &, Types... > *)
Definition: FunctionWrapper.h:164
T *(*)(const ScriptRequest &, JS::CallArgs &) ObjectGetter
Definition: FunctionWrapper.h:264
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:340
Abstraction around a SpiderMonkey JS::Realm.
Definition: ScriptInterface.h:72
Spidermonkey maintains some 'local' state via the JSContext* object.
Definition: ScriptRequest.h:60
const ScriptInterface & GetScriptInterface() const
Return the scriptInterface active when creating this ScriptRequest.
Definition: ScriptInterface.cpp:98
JS::Value globalValue() const
Definition: ScriptInterface.cpp:93
JSContext * cx
Definition: ScriptRequest.h:92
JS::HandleObject nativeScope
Definition: ScriptRequest.h:94
#define UNUSED2(param)
mark a function local variable or parameter as unused and avoid the corresponding compiler warning.
Definition: code_annotation.h:58
void ignore_result(const T &)
Silence the 'unused result' warning.
Definition: code_annotation.h:67
bool IsPending(const ScriptRequest &rq)
Definition: ScriptExceptions.cpp:28
bool CatchPending(const ScriptRequest &rq)
Log and then clear the current pending exception.
Definition: ScriptExceptions.cpp:33
bool FromJSVal(const ScriptRequest &rq, const JS::HandleValue val, T &ret)
Convert a JS::Value to a C++ type.
void ToJSVal(const ScriptRequest &rq, JS::MutableHandleValue ret, T const &val)
Convert a C++ type to a JS::Value.
bool FromJSProperty(const ScriptRequest &rq, const JS::HandleValue val, const char *name, T &ret, bool strict=false)
Convert a named property of an object to a C++ type.
Definition: ScriptConversions.h:71
bool error(JSContext *cx, uint argc, JS::Value *vp)
Definition: ScriptInterface.cpp:173
Definition: ShaderDefines.cpp:31
#define T(string_literal)
Definition: secure_crt.cpp:77
Definition: FunctionWrapper.h:202
Definition: FunctionWrapper.h:86
IteratorResultError(const char *property)
Definition: FunctionWrapper.h:90
IteratorResultError(const std::string &property)
Definition: FunctionWrapper.h:87
std::tuple< type_transform< Types >... > arg_types
Definition: FunctionWrapper.h:77
void object_type
Definition: FunctionWrapper.h:76
R return_type
Definition: FunctionWrapper.h:75
Convenient struct to get info on a [class] [const] function pointer.
Definition: FunctionWrapper.h:69
uint16_t u16
Definition: types.h:38