1
0
forked from 0ad/0ad

Implements CallFunction with JS::MutableHandle<T> return type.

Changes the CallFunction implementation to use macros because otherwise
we'd have to write twice as many functions manually.
Adapts GetSavedGameData to use the new function template. Additional
callers will be changed in future commits.

Refs #2415
Refs #2462

This was SVN commit r15541.
This commit is contained in:
Yves 2014-07-20 15:08:28 +00:00
parent 3782857333
commit 31f9ca9ebf
4 changed files with 68 additions and 118 deletions

View File

@ -261,11 +261,14 @@ Status CGUIManager::ReloadChangedFile(const VfsPath& path)
CScriptVal CGUIManager::GetSavedGameData(ScriptInterface*& pPageScriptInterface)
{
CScriptVal data;
if (!top()->GetScriptInterface()->CallFunction(top()->GetGlobalObject(), "getSavedGameData", data))
JSContext* cx = top()->GetScriptInterface()->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue data(cx);
if (!top()->GetScriptInterface()->CallFunction(top()->GetGlobalObject(), "getSavedGameData", &data))
LOGERROR(L"Failed to call getSavedGameData() on the current GUI page");
pPageScriptInterface = GetScriptInterface().get();
return data;
return CScriptVal(data);
}
std::string CGUIManager::GetSavedGameData()

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2014 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -26,6 +26,7 @@
#define NUMBERED_LIST_BALANCED(z, i, data) BOOST_PP_COMMA_IF(i) data##i
// Some other things
#define TYPED_ARGS(z, i, data) , T##i a##i
#define TYPED_ARGS_CONST_REF(z, i, data) const T##i& a##i,
#define CONVERT_ARG(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal<T##i>(cx, i < args.length() ? args.handleAt(i) : JS::UndefinedHandleValue, a##i)) return false;
// List-generating macros, named roughly after their first list item
@ -35,6 +36,7 @@
#define T0_HEAD(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_HEAD, T) // "T0, T1, "
#define T0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, T) // ", T0, T1"
#define T0_A0(z, i) BOOST_PP_REPEAT_##z (i, TYPED_ARGS, ~) // "T0 a0, T1 a1"
#define T0_A0_CONST_REF(z, i) BOOST_PP_REPEAT_##z (i, TYPED_ARGS_CONST_REF, ~) // " const T0 a0, const T1 a1, "
#define A0(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_BALANCED, a) // "a0, a1"
#define A0_TAIL(z, i) BOOST_PP_REPEAT_##z (i, NUMBERED_LIST_TAIL, a) // ", a0, a1"
@ -68,3 +70,19 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
static size_t nargs() { return i; }
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
// Call the named property on the given object
#define OVERLOADS(z, i, data) \
template <typename R TYPENAME_T0_TAIL(z, i)> \
bool CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) R& ret);
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
// The trick is using JS::Rooted<R>* and converting that to a JS::MutableHandle<R> explicitly in the function body.
// Normally the function would take JS::MutableHandle<R> and that conversion would happen implicitly. However, implicit
// conversion does not work with template argument deduction (only exact type matches allowed).
#define OVERLOADS(z, i, data) \
template <typename R TYPENAME_T0_TAIL(z, i)> \
bool CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) JS::Rooted<R>* ret);
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2014 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -123,11 +123,52 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
#define TO_JS_VAL(z, i, data) ToJSVal(cx, argv.handleAt(i), a##i);
#define OVERLOADS(z, i, data) \
template<typename R TYPENAME_T0_TAIL(z, i)> \
bool ScriptInterface::CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) R& ret) \
{ \
JSContext* cx = GetContext(); \
JSAutoRequest rq(cx); \
JS::RootedValue jsRet(cx); \
JS::RootedValue val1(cx, val); \
JS::AutoValueVector argv(cx); \
argv.resize(i); \
BOOST_PP_REPEAT_##z (i, TO_JS_VAL, ~) \
bool ok = CallFunction_(val1, name, argv.length(), argv.begin(), &jsRet); \
if (!ok) \
return false; \
return FromJSVal(cx, jsRet, ret); \
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
#define OVERLOADS(z, i, data) \
template<typename R TYPENAME_T0_TAIL(z, i)> \
bool ScriptInterface::CallFunction(jsval val, const char* name, T0_A0_CONST_REF(z,i) JS::Rooted<R>* ret) \
{ \
JSContext* cx = GetContext(); \
JSAutoRequest rq(cx); \
JS::MutableHandle<R> jsRet(ret); \
JS::RootedValue val1(cx, val); \
JS::AutoValueVector argv(cx); \
argv.resize(i); \
BOOST_PP_REPEAT_##z (i, TO_JS_VAL, ~) \
bool ok = CallFunction_(val1, name, argv.length(), argv.begin(), jsRet); \
if (!ok) \
return false; \
return true; \
}
BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef OVERLOADS
// Clean up our mess
#undef SCRIPT_PROFILE
#undef NUMBERED_LIST_HEAD
#undef NUMBERED_LIST_TAIL
#undef NUMBERED_LIST_BALANCED
#undef TYPED_ARGS_CONST_REF
#undef TYPED_ARGS
#undef CONVERT_ARG
#undef TYPENAME_T0_HEAD
@ -135,6 +176,7 @@ BOOST_PP_REPEAT(SCRIPT_INTERFACE_MAX_ARGS, OVERLOADS, ~)
#undef T0
#undef T0_HEAD
#undef T0_TAIL
#undef T0_A0_CONST_REF
#undef T0_A0
#undef A0
#undef A0_TAIL

View File

@ -170,36 +170,6 @@ public:
template<typename T0, typename T1, typename T2>
bool CallFunctionVoid(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2);
/**
* Call the named property on the given object, with return type R and 0 arguments
*/
template<typename R>
bool CallFunction(jsval val, const char* name, R& ret);
/**
* Call the named property on the given object, with return type R and 1 argument
*/
template<typename T0, typename R>
bool CallFunction(jsval val, const char* name, const T0& a0, R& ret);
/**
* Call the named property on the given object, with return type R and 2 arguments
*/
template<typename T0, typename T1, typename R>
bool CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, R& ret);
/**
* Call the named property on the given object, with return type R and 3 arguments
*/
template<typename T0, typename T1, typename T2, typename R>
bool CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, R& ret);
/**
* Call the named property on the given object, with return type R and 4 arguments
*/
template<typename T0, typename T1, typename T2, typename T3, typename R>
bool CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, const T3& a3, R& ret);
JSObject* CreateCustomObject(const std::string & typeName);
void DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs);
@ -444,19 +414,6 @@ public:
// Implement those declared functions
#include "NativeWrapperDefns.h"
template<typename R>
bool ScriptInterface::CallFunction(jsval val, const char* name, R& ret)
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::RootedValue val1(cx, val);
bool ok = CallFunction_(val1, name, 0, NULL, &jsRet);
if (!ok)
return false;
return FromJSVal(GetContext(), jsRet, ret);
}
template<typename T0>
bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0)
{
@ -499,76 +456,6 @@ bool ScriptInterface::CallFunctionVoid(jsval val, const char* name, const T0& a0
return CallFunction_(val1, name, 3, argv.begin(), &jsRet);
}
template<typename T0, typename R>
bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, R& ret)
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::RootedValue val1(cx, val);
JS::AutoValueVector argv(cx);
argv.resize(1);
ToJSVal(cx, argv.handleAt(0), a0);
bool ok = CallFunction_(val1, name, 1, argv.begin(), &jsRet);
if (!ok)
return false;
return FromJSVal(cx, jsRet, ret);
}
template<typename T0, typename T1, typename R>
bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, R& ret)
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::RootedValue val1(cx, val);
JS::AutoValueVector argv(cx);
argv.resize(2);
ToJSVal(cx, argv.handleAt(0), a0);
ToJSVal(cx, argv.handleAt(1), a1);
bool ok = CallFunction_(val1, name, 2, argv.begin(), &jsRet);
if (!ok)
return false;
return FromJSVal(cx, jsRet, ret);
}
template<typename T0, typename T1, typename T2, typename R>
bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, R& ret)
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::RootedValue val1(cx, val);
JS::AutoValueVector argv(cx);
argv.resize(3);
ToJSVal(cx, argv.handleAt(0), a0);
ToJSVal(cx, argv.handleAt(1), a1);
ToJSVal(cx, argv.handleAt(2), a2);
bool ok = CallFunction_(val1, name, 3, argv.begin(), &jsRet);
if (!ok)
return false;
return FromJSVal(cx, jsRet, ret);
}
template<typename T0, typename T1, typename T2, typename T3, typename R>
bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, const T3& a3, R& ret)
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
JS::RootedValue jsRet(cx);
JS::RootedValue val1(cx, val);
JS::AutoValueVector argv(cx);
argv.resize(4);
ToJSVal(cx, argv.handleAt(0), a0);
ToJSVal(cx, argv.handleAt(1), a1);
ToJSVal(cx, argv.handleAt(2), a2);
ToJSVal(cx, argv.handleAt(3), a3);
bool ok = CallFunction_(val1, name, 4, argv.begin(), &jsRet);
if (!ok)
return false;
return FromJSVal(cx, jsRet, ret);
}
template<typename T>
bool ScriptInterface::SetGlobal(const char* name, const T& value, bool replace)
{