Pyrogenesis HEAD
Pyrogenesis, a RTS Engine
ScriptConversions.h
Go to the documentation of this file.
1/* Copyright (C) 2021 Wildfire Games.
2 * This file is part of 0 A.D.
3 *
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef INCLUDED_SCRIPTCONVERSIONS
19#define INCLUDED_SCRIPTCONVERSIONS
20
21#include "ScriptRequest.h"
22#include "ScriptExceptions.h"
23#include "ScriptExtraHeaders.h" // for typed arrays
24
25#include <limits>
26#include <vector>
27
28namespace Script
29{
30/**
31 * Convert a JS::Value to a C++ type. (This might trigger GC.)
32 */
33template<typename T> bool FromJSVal(const ScriptRequest& rq, const JS::HandleValue val, T& ret);
34
35/**
36 * Convert a C++ type to a JS::Value. (This might trigger GC. The return
37 * value must be rooted if you don't want it to be collected.)
38 * NOTE: We are passing the JS::Value by reference instead of returning it by value.
39 * The reason is a memory corruption problem that appears to be caused by a bug in Visual Studio.
40 * Details here: http://www.wildfiregames.com/forum/index.php?showtopic=17289&p=285921
41 */
42template<typename T> void ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, T const& val);
43
44template<>
45inline void ToJSVal<JS::PersistentRootedValue>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::PersistentRootedValue& a)
46{
47 handle.set(a);
48}
49
50template<>
51inline void ToJSVal<JS::Heap<JS::Value> >(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::Heap<JS::Value>& a)
52{
53 handle.set(a);
54}
55
56template<>
57inline void ToJSVal<JS::RootedValue>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::RootedValue& a)
58{
59 handle.set(a);
60}
61
62template <>
63inline void ToJSVal<JS::HandleValue>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue handle, const JS::HandleValue& a)
64{
65 handle.set(a);
66}
67
68/**
69 * Convert a named property of an object to a C++ type.
70 */
71template<typename T> inline bool FromJSProperty(const ScriptRequest& rq, const JS::HandleValue val, const char* name, T& ret, bool strict = false)
72{
73 if (!val.isObject())
74 return false;
75
76 JS::RootedObject obj(rq.cx, &val.toObject());
77
78 bool hasProperty;
79 if (!JS_HasProperty(rq.cx, obj, name, &hasProperty) || !hasProperty)
80 return false;
81
82 JS::RootedValue value(rq.cx);
83 if (!JS_GetProperty(rq.cx, obj, name, &value))
84 return false;
85
86 if (strict && value.isNull())
87 return false;
88
89 return FromJSVal(rq, value, ret);
90}
91
92template<typename T> inline void ToJSVal_vector(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::vector<T>& val)
93{
94 JS::RootedObject obj(rq.cx, JS::NewArrayObject(rq.cx, 0));
95 if (!obj)
96 {
97 ret.setUndefined();
98 return;
99 }
100
101 ENSURE(val.size() <= std::numeric_limits<u32>::max());
102 for (u32 i = 0; i < val.size(); ++i)
103 {
104 JS::RootedValue el(rq.cx);
105 Script::ToJSVal<T>(rq, &el, val[i]);
106 JS_SetElement(rq.cx, obj, i, el);
107 }
108 ret.setObject(*obj);
109}
110
111#define FAIL(msg) STMT(ScriptException::Raise(rq, msg); return false)
112
113template<typename T> inline bool FromJSVal_vector(const ScriptRequest& rq, JS::HandleValue v, std::vector<T>& out)
114{
115 JS::RootedObject obj(rq.cx);
116 if (!v.isObject())
117 FAIL("Argument must be an array");
118
119 bool isArray;
120 obj = &v.toObject();
121 if ((!JS::IsArrayObject(rq.cx, obj, &isArray) || !isArray) && !JS_IsTypedArrayObject(obj))
122 FAIL("Argument must be an array");
123
124 u32 length;
125 if (!JS::GetArrayLength(rq.cx, obj, &length))
126 FAIL("Failed to get array length");
127
128 out.clear();
129 out.reserve(length);
130 for (u32 i = 0; i < length; ++i)
131 {
132 JS::RootedValue el(rq.cx);
133 if (!JS_GetElement(rq.cx, obj, i, &el))
134 FAIL("Failed to read array element");
135 T el2;
136 if (!Script::FromJSVal<T>(rq, el, el2))
137 return false;
138 out.push_back(el2);
139 }
140 return true;
141}
142
143#undef FAIL
144
145#define JSVAL_VECTOR(T) \
146template<> void Script::ToJSVal<std::vector<T> >(const ScriptRequest& rq, JS::MutableHandleValue ret, const std::vector<T>& val) \
147{ \
148 ToJSVal_vector(rq, ret, val); \
149} \
150template<> bool Script::FromJSVal<std::vector<T> >(const ScriptRequest& rq, JS::HandleValue v, std::vector<T>& out) \
151{ \
152 return FromJSVal_vector(rq, v, out); \
153}
154
155} // namespace Script
156
157#endif //INCLUDED_SCRIPTCONVERSIONS
#define FAIL(msg)
Definition: ScriptConversions.h:111
Spidermonkey maintains some 'local' state via the JSContext* object.
Definition: ScriptRequest.h:60
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:40
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
Definition: debug.h:277
Wraps SM APIs for manipulating JS objects.
Definition: JSON.h:35
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
void ToJSVal_vector(const ScriptRequest &rq, JS::MutableHandleValue ret, const std::vector< T > &val)
Definition: ScriptConversions.h:92
bool FromJSVal_vector(const ScriptRequest &rq, JS::HandleValue v, std::vector< T > &out)
Definition: ScriptConversions.h:113
#define T(string_literal)
Definition: secure_crt.cpp:77
uint32_t u32
Definition: types.h:39
static void out(const wchar_t *fmt,...)
Definition: wdbg_sym.cpp:407