Overte C++ Documentation
ScriptEngineCast.h
1 //
2 // ScriptEngineCast.h
3 // libraries/script-engine/src
4 //
5 // Created by Heather Anderson on 5/9/2021.
6 // Copyright 2021 Vircadia contributors.
7 // Copyright 2022-2023 Overte e.V.
8 //
9 // Distributed under the Apache License, Version 2.0.
10 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
11 // SPDX-License-Identifier: Apache-2.0
12 //
13 
16 
17 #ifndef hifi_ScriptEngineCast_h
18 #define hifi_ScriptEngineCast_h
19 
20 // Object conversion helpers (copied from QScriptEngine)
21 
22 #include <QtCore/QMetaType>
23 #include <QtCore/QMetaEnum>
24 #include <QtCore/QDebug>
25 
26 #include "ScriptEngine.h"
27 #include "ScriptValue.h"
28 
29 template <typename T>
30 inline ScriptValue scriptValueFromValue(ScriptEngine* engine, const T& t) {
31  if (!engine) {
32  return ScriptValue();
33  }
34 
35  return engine->create(qMetaTypeId<T>(), &t);
36 }
37 
38 template <>
39 inline ScriptValue scriptValueFromValue<QVariant>(ScriptEngine* engine, const QVariant& v) {
40  if (!engine) {
41  return ScriptValue();
42  }
43 
44  return engine->create(v.userType(), v.data());
45 }
46 
47 // V8TODO: run through debugger for AnimationPointer/AnimationObject
48 template <typename T>
49 inline T scriptvalue_cast(const ScriptValue& value) {
50  const int id = qMetaTypeId<T>();
51 
52  auto engine = value.engine();
53  if (engine) {
54  QVariant varValue = engine->convert(value, id);
55  if (varValue.isValid()) {
56  return varValue.value<T>();
57  }
58  }
59  if (value.isVariant()) {
60  return qvariant_cast<T>(value.toVariant());
61  }
62 
63  return T();
64 }
65 
66 template <>
67 inline QVariant scriptvalue_cast<QVariant>(const ScriptValue& value) {
68  return value.toVariant();
69 }
70 
71 template <typename T, ScriptValue (*f)(ScriptEngine*, const T&)>
72 ScriptValue toScriptValueWrapper(ScriptEngine* engine, const void *p) {
73  Q_ASSERT(p != NULL);
74  auto &src = *(reinterpret_cast<const T*>(p));
75  return f(engine, src);
76 }
77 
78 template <typename T, bool (*f)(const ScriptValue&, T&)>
79 bool fromScriptValueWrapper(const ScriptValue& val, QVariant &destV) {
80  //auto &dest = *(reinterpret_cast<T*>(p));
81  T dest;
82  bool result = f(val, dest);
83  destV.setValue(dest);
84  return result;
85 }
86 
87 template <typename T, ScriptValue (*toScriptValue)(ScriptEngine*, const T&), bool (*fromScriptValue)(const ScriptValue&, T&)>
88 int scriptRegisterMetaType(ScriptEngine* eng, const char* name = "",
89  T* = 0)
90 {
91  int id;
92  if (strlen(name) > 0) { // make sure it's registered
93  id = qRegisterMetaType<T>(name);
94  } else {
95  id = qRegisterMetaType<T>();
96  }
97  eng->registerCustomType(id, toScriptValueWrapper<T, toScriptValue>,
98  fromScriptValueWrapper<T, fromScriptValue>);
99  return id;
100 }
101 
102 // This can be safely removed and replaced with scriptRegisterMetaType once we use C++20 everywhere
103 template <typename T>
104 int scriptRegisterMetaTypeWithLambdas(ScriptEngine* eng,
105  ScriptValue (*toScriptValue)(ScriptEngine*, const void *),
106  bool (*fromScriptValue)(const ScriptValue&, QVariant &dest), const char* name = "",
107  T* = 0)
108 {
109  int id;
110  if (strlen(name) > 0) { // make sure it's registered
111  id = qRegisterMetaType<T>(name);
112  } else {
113  id = qRegisterMetaType<T>();
114  }
115  eng->registerCustomType(id, toScriptValue,
116  fromScriptValue);
117  return id;
118 }
119 
120 template <class Container>
121 ScriptValue scriptValueFromSequence(ScriptEngine* eng, const Container& cont) {
122  ScriptValue a = eng->newArray();
123  typename Container::const_iterator begin = cont.begin();
124  typename Container::const_iterator end = cont.end();
125  typename Container::const_iterator it;
126  quint32 i;
127  for (it = begin, i = 0; it != end; ++it, ++i) {
128  a.setProperty(i, eng->toScriptValue(*it));
129  }
130  return a;
131 }
132 
133 template <class Container>
134 bool scriptValueToSequence(const ScriptValue& value, Container& cont) {
135  quint32 len = value.property(QLatin1String("length")).toUInt32();
136  for (quint32 i = 0; i < len; ++i) {
137  ScriptValue item = value.property(i);
138  cont.push_back(scriptvalue_cast<typename Container::value_type>(item));
139  }
140  return true;
141 }
142 
143 template <class T>
144 ScriptValue scriptValueFromEnumClass(ScriptEngine* eng, const T& enumValue) {
145  ScriptValue a = eng->newValue(static_cast<int>(enumValue));
146  return a;
147 }
148 
149 template <class T>
150 bool scriptValueToEnumClass(const ScriptValue& value, T& enumValue) {
151  if(!value.isNumber()){
152  qCDebug(scriptengine) << "ScriptValue \"" << value.toQObject()->metaObject()->className() << "\" is not a number";
153  return false;
154  }
155  QMetaEnum metaEnum = QMetaEnum::fromType<T>();
156  if (!metaEnum.isValid()) {
157  qCDebug(scriptengine) << "Invalid QMetaEnum";
158  return false;
159  }
160  bool isValid = false;
161  int enumInteger = static_cast<int>(value.toInteger());
162  for(int i = 0; i < metaEnum.keyCount(); i++){
163  if (metaEnum.value(i) == enumInteger) {
164  isValid = true;
165  break;
166  }
167  }
168  if (isValid) {
169  enumValue = static_cast<T>(enumInteger);
170  return true;
171  } else {
172  qCDebug(scriptengine) << "ScriptValue has invalid value " << value.toInteger() << " for enum" << metaEnum.name();
173  return false;
174  }
175 }
176 
177 template <typename T>
178 int scriptRegisterSequenceMetaType(ScriptEngine* engine,
179  T* = 0) {
180  return scriptRegisterMetaType<T, scriptValueFromSequence, scriptValueToSequence>(engine);
181 }
182 
183 #endif // hifi_ScriptEngineCast_h
184 
Provides an engine-independent interface for a scripting engine.
Definition: ScriptEngine.h:93
[ScriptInterface] Provides an engine-independent interface for QScriptValue
Definition: ScriptValue.h:40