Pyrogenesis  trunk
Classes | Public Types | Static Public Member Functions | Private Types | Private Member Functions | Static Private Member Functions | Static Private Attributes | List of all members
ScriptFunction Class Reference

This class introduces templates to conveniently wrap C++ functions in JSNative functions. More...

#include <FunctionWrapper.h>

Collaboration diagram for ScriptFunction:
Collaboration graph
[legend]

Classes

struct  args_info
 Convenient struct to get info on a [class] [const] function pointer. More...
 
struct  args_info< R(*)(Types ...)>
 
struct  args_info< R(C::*)(Types ...) const >
 
struct  args_info< R(C::*)(Types ...)>
 
struct  IgnoreResult_t
 

Public Types

template<typename T >
using ObjectGetter = T *(*)(const ScriptRequest &, JS::CallArgs &)
 
template<class callableType >
using GetterFor = ObjectGetter< typename args_info< callableType >::object_type >
 

Static Public Member Functions

template<auto callable, GetterFor< decltype(callable)> thisGetter = nullptr>
static bool ToJSNative (JSContext *cx, unsigned argc, JS::Value *vp)
 The meat of this file. More...
 
template<typename R , typename ... Args>
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. More...
 
template<typename ... Args>
static bool Call (const ScriptRequest &rq, JS::HandleValue val, const char *name, JS::MutableHandleValue ret, const Args &... args)
 
template<typename ... Args>
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. More...
 
template<auto callable, GetterFor< decltype(callable)> thisGetter = nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
static JSFunctionSpec Wrap (const char *name)
 Return a function spec from a C++ function. More...
 
template<auto callable, GetterFor< decltype(callable)> thisGetter = nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
static JSFunction * Create (const ScriptRequest &rq, const char *name)
 Return a JSFunction from a C++ function. More...
 
template<auto callable, GetterFor< decltype(callable)> thisGetter = nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
static void Register (const ScriptRequest &rq, const char *name)
 Register a function on the native scope (usually 'Engine'). More...
 
template<auto callable, GetterFor< decltype(callable)> thisGetter = nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
static void Register (JSContext *cx, JS::HandleObject scope, const char *name)
 Register a function on. More...
 

Private Types

template<typename T >
using type_transform = 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 > > >
 In JS->C++ calls, types are converted using FromJSVal, and this requires them to be default-constructible (as that function takes an out parameter) thus constref needs to be removed when defining the tuple. More...
 

Private Member Functions

 ScriptFunction ()=delete
 
 ScriptFunction (const ScriptFunction &)=delete
 
 ScriptFunction (ScriptFunction &&)=delete
 

Static Private Member Functions

template<size_t idx, typename T >
static std::tuple< TDoConvertFromJS (const ScriptRequest &rq, JS::CallArgs &args, bool &went_ok)
 DoConvertFromJS takes a type, a JS argument, and converts. More...
 
template<size_t idx, typename T , typename V , typename ... Types>
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. More...
 
template<typename ... Types>
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: More...
 
template<typename ... Types>
static std::tuple< const ScriptRequest &, Types... > ConvertFromJS (const ScriptRequest &rq, JS::CallArgs &args, bool &went_ok, std::tuple< const ScriptRequest &, Types... > *)
 
template<typename ... Types>
static std::tuple< const ScriptInterface &, Types... > ConvertFromJS (const ScriptRequest &rq, JS::CallArgs &args, bool &went_ok, std::tuple< const ScriptInterface &, Types... > *)
 
template<auto callable, typename T , typename tuple >
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. More...
 
template<int i, typename T , typename... Ts>
static void AssignOrToJSValHelper (const ScriptRequest &rq, JS::MutableHandleValueVector argv, const T &a, const Ts &... params)
 Recursive helper to call AssignOrToJSVal. More...
 
template<int i, typename... Ts>
static void AssignOrToJSValHelper (const ScriptRequest &rq, JS::MutableHandleValueVector argv)
 
template<typename R , typename ... Args>
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++. More...
 

Static Private Attributes

static IgnoreResult_t IgnoreResult
 

Detailed Description

This class introduces templates to conveniently wrap C++ functions in JSNative functions.

This is rather template heavy, so compilation times beware. The C++ code can have arbitrary arguments and arbitrary return types, so long as they can be converted to/from JS using Script::ToJSVal (FromJSVal respectively), and they are default-constructible (TODO: that can probably changed). (This could be a namespace, but I like being able to specify public/private).

Member Typedef Documentation

◆ GetterFor

template<class callableType >
using ScriptFunction::GetterFor = ObjectGetter<typename args_info<callableType>::object_type>

◆ ObjectGetter

template<typename T >
using ScriptFunction::ObjectGetter = T*(*)(const ScriptRequest&, JS::CallArgs&)

◆ type_transform

template<typename T >
using ScriptFunction::type_transform = 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> > >
private

In JS->C++ calls, types are converted using FromJSVal, and this requires them to be default-constructible (as that function takes an out parameter) thus constref needs to be removed when defining the tuple.

Exceptions are:

  • const ScriptRequest& (as the first argument only, for implementation simplicity).
  • const ScriptInterface& (as the first argument only, for implementation simplicity).
  • JS::HandleValue

Constructor & Destructor Documentation

◆ ScriptFunction() [1/3]

ScriptFunction::ScriptFunction ( )
privatedelete

◆ ScriptFunction() [2/3]

ScriptFunction::ScriptFunction ( const ScriptFunction )
privatedelete

◆ ScriptFunction() [3/3]

ScriptFunction::ScriptFunction ( ScriptFunction &&  )
privatedelete

Member Function Documentation

◆ AssignOrToJSValHelper() [1/2]

template<int i, typename T , typename... Ts>
static void ScriptFunction::AssignOrToJSValHelper ( const ScriptRequest rq,
JS::MutableHandleValueVector  argv,
const T a,
const Ts &...  params 
)
inlinestaticprivate

Recursive helper to call AssignOrToJSVal.

◆ AssignOrToJSValHelper() [2/2]

template<int i, typename... Ts>
static void ScriptFunction::AssignOrToJSValHelper ( const ScriptRequest rq,
JS::MutableHandleValueVector  argv 
)
inlinestaticprivate

◆ call()

template<auto callable, typename T , typename tuple >
static args_info<decltype(callable)>::return_type ScriptFunction::call ( T object,
tuple &  args 
)
inlinestaticprivate

Wrap std::apply for the case where we have an object method or a regular function.

◆ Call() [1/2]

template<typename R , typename ... Args>
static bool ScriptFunction::Call ( const ScriptRequest rq,
JS::HandleValue  val,
const char *  name,
R &  ret,
const Args &...  args 
)
inlinestatic

Call a JS function name, property of object val, with the arguments args.

ret will be updated with the return value, if any.

Returns
the success (or failure) thereof.

◆ Call() [2/2]

template<typename ... Args>
static bool ScriptFunction::Call ( const ScriptRequest rq,
JS::HandleValue  val,
const char *  name,
JS::MutableHandleValue  ret,
const Args &...  args 
)
inlinestatic

◆ Call_()

template<typename R , typename ... Args>
static bool ScriptFunction::Call_ ( const ScriptRequest rq,
JS::HandleValue  val,
const char *  name,
R &  ret,
const Args &...  args 
)
inlinestaticprivate

Wrapper around calling a JS function from C++.

Arguments are const& to avoid lvalue/rvalue issues, and so can't be used as out-parameters. In particular, the problem is that Rooted are deduced as Rooted, not Handle, and so can't be copied. This could be worked around with more templates, but it doesn't seem particularly worth doing.

◆ CallVoid()

template<typename ... Args>
static bool ScriptFunction::CallVoid ( const ScriptRequest rq,
JS::HandleValue  val,
const char *  name,
const Args &...  args 
)
inlinestatic

Call a JS function name, property of object val, with the arguments args.

Returns
the success (or failure) thereof.

◆ ConvertFromJS() [1/3]

template<typename ... Types>
static std::tuple<Types...> ScriptFunction::ConvertFromJS ( const ScriptRequest rq,
JS::CallArgs &  args,
bool &  went_ok,
std::tuple< Types... > *   
)
inlinestaticprivate

ConvertFromJS is a wrapper around DoConvertFromJS, and serves to:

  • unwrap the tuple types as a parameter pack
  • handle specific cases for the first argument (ScriptRequest, ...).

Trick: to unpack the types of the tuple as a parameter pack, we deduce them from the function signature. To do that, we want the tuple in the arguments, but we don't want to actually have to default-instantiate, so we'll pass a nullptr that's static_cast to what we want.

◆ ConvertFromJS() [2/3]

template<typename ... Types>
static std::tuple<const ScriptRequest&, Types...> ScriptFunction::ConvertFromJS ( const ScriptRequest rq,
JS::CallArgs &  args,
bool &  went_ok,
std::tuple< const ScriptRequest &, Types... > *   
)
inlinestaticprivate

◆ ConvertFromJS() [3/3]

template<typename ... Types>
static std::tuple<const ScriptInterface&, Types...> ScriptFunction::ConvertFromJS ( const ScriptRequest rq,
JS::CallArgs &  args,
bool &  went_ok,
std::tuple< const ScriptInterface &, Types... > *   
)
inlinestaticprivate

◆ Create()

template<auto callable, GetterFor< decltype(callable)> thisGetter = nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
static JSFunction* ScriptFunction::Create ( const ScriptRequest rq,
const char *  name 
)
inlinestatic

Return a JSFunction from a C++ function.

◆ DoConvertFromJS() [1/2]

template<size_t idx, typename T >
static std::tuple<T> ScriptFunction::DoConvertFromJS ( const ScriptRequest rq,
JS::CallArgs &  args,
bool &  went_ok 
)
inlinestaticprivate

DoConvertFromJS takes a type, a JS argument, and converts.

The type T must be default constructible (except for HandleValue, which is handled specially). (possible) TODO: this could probably be changed if FromJSVal had a different signature.

Parameters
went_ok- true if the conversion succeeded and went_ok was true before, false otherwise.

◆ DoConvertFromJS() [2/2]

template<size_t idx, typename T , typename V , typename ... Types>
static std::tuple<T, V, Types...> ScriptFunction::DoConvertFromJS ( const ScriptRequest rq,
JS::CallArgs &  args,
bool &  went_ok 
)
inlinestaticprivate

Recursive wrapper: calls DoConvertFromJS for type T and recurses.

◆ Register() [1/2]

template<auto callable, GetterFor< decltype(callable)> thisGetter = nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
static void ScriptFunction::Register ( const ScriptRequest rq,
const char *  name 
)
inlinestatic

Register a function on the native scope (usually 'Engine').

◆ Register() [2/2]

template<auto callable, GetterFor< decltype(callable)> thisGetter = nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
static void ScriptFunction::Register ( JSContext *  cx,
JS::HandleObject  scope,
const char *  name 
)
inlinestatic

Register a function on.

Parameters
scope.Prefer the version taking ScriptRequest unless you have a good reason not to.
See also
Register

◆ ToJSNative()

template<auto callable, GetterFor< decltype(callable)> thisGetter = nullptr>
static bool ScriptFunction::ToJSNative ( JSContext *  cx,
unsigned  argc,
JS::Value *  vp 
)
inlinestatic

The meat of this file.

This wraps a C++ function into a JSNative, so that it can be called from JS and manipulated in Spidermonkey. Most C++ functions can be directly wrapped, so long as their arguments are convertible from JS::Value and their return value is convertible to JS::Value (or void) The C++ function may optionally take const ScriptRequest& or ScriptInterface& as its first argument. The function may be an object method, in which case you need to pass an appropriate getter

Optimisation note: the ScriptRequest object is created even without arguments, as it's necessary for IsExceptionPending.

Parameters
thisGetterto get the object, if necessary.

TODO: error handling isn't standard, and since this can call any C++ function, there's no simple obvious way to deal with it. For now we check for pending JS exceptions, but it would probably be nicer to standardise on something, or perhaps provide an "errorHandler" here.

◆ Wrap()

template<auto callable, GetterFor< decltype(callable)> thisGetter = nullptr, u16 flags = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT>
static JSFunctionSpec ScriptFunction::Wrap ( const char *  name)
inlinestatic

Return a function spec from a C++ function.

Member Data Documentation

◆ IgnoreResult

IgnoreResult_t ScriptFunction::IgnoreResult
inlinestaticprivate

The documentation for this class was generated from the following file: