// // ScriptEngineCast.h // libraries/script-engine/src // // Created by Heather Anderson on 5/9/2021. // Copyright 2021 Vircadia contributors. // Copyright 2022-2023 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // SPDX-License-Identifier: Apache-2.0 // /// @addtogroup ScriptEngine /// @{ #ifndef hifi_ScriptEngineCast_h #define hifi_ScriptEngineCast_h // Object conversion helpers (copied from QScriptEngine) #include #include #include #include "ScriptEngine.h" #include "ScriptValue.h" template inline ScriptValue scriptValueFromValue(ScriptEngine* engine, const T& t) { if (!engine) { return ScriptValue(); } return engine->create(qMetaTypeId(), &t); } template <> inline ScriptValue scriptValueFromValue(ScriptEngine* engine, const QVariant& v) { if (!engine) { return ScriptValue(); } return engine->create(v.userType(), v.data()); } // V8TODO: run through debugger for AnimationPointer/AnimationObject template inline T scriptvalue_cast(const ScriptValue& value) { const int id = qMetaTypeId(); auto engine = value.engine(); if (engine) { QVariant varValue = engine->convert(value, id); if (varValue.isValid()) { return varValue.value(); } } if (value.isVariant()) { return qvariant_cast(value.toVariant()); } return T(); } template <> inline QVariant scriptvalue_cast(const ScriptValue& value) { return value.toVariant(); } template ScriptValue toScriptValueWrapper(ScriptEngine* engine, const void *p) { Q_ASSERT(p != NULL); auto &src = *(reinterpret_cast(p)); return f(engine, src); } template bool fromScriptValueWrapper(const ScriptValue& val, QVariant &destV) { //auto &dest = *(reinterpret_cast(p)); T dest; bool result = f(val, dest); destV.setValue(dest); return result; } template int scriptRegisterMetaType(ScriptEngine* eng, const char* name = "", T* = 0) { int id; if (strlen(name) > 0) { // make sure it's registered id = qRegisterMetaType(name); } else { id = qRegisterMetaType(); } eng->registerCustomType(id, toScriptValueWrapper, fromScriptValueWrapper); return id; } // This can be safely removed and replaced with scriptRegisterMetaType once we use C++20 everywhere template int scriptRegisterMetaTypeWithLambdas(ScriptEngine* eng, ScriptValue (*toScriptValue)(ScriptEngine*, const void *), bool (*fromScriptValue)(const ScriptValue&, QVariant &dest), const char* name = "", T* = 0) { int id; if (strlen(name) > 0) { // make sure it's registered id = qRegisterMetaType(name); } else { id = qRegisterMetaType(); } eng->registerCustomType(id, toScriptValue, fromScriptValue); return id; } template ScriptValue scriptValueFromSequence(ScriptEngine* eng, const Container& cont) { ScriptValue a = eng->newArray(); typename Container::const_iterator begin = cont.begin(); typename Container::const_iterator end = cont.end(); typename Container::const_iterator it; quint32 i; for (it = begin, i = 0; it != end; ++it, ++i) { a.setProperty(i, eng->toScriptValue(*it)); } return a; } template bool scriptValueToSequence(const ScriptValue& value, Container& cont) { quint32 len = value.property(QLatin1String("length")).toUInt32(); for (quint32 i = 0; i < len; ++i) { ScriptValue item = value.property(i); cont.push_back(scriptvalue_cast(item)); } return true; } template ScriptValue scriptValueFromEnumClass(ScriptEngine* eng, const T& enumValue) { ScriptValue a = eng->newValue(static_cast(enumValue)); return a; } template bool scriptValueToEnumClass(const ScriptValue& value, T& enumValue) { if(!value.isNumber()){ qCDebug(scriptengine) << "ScriptValue \"" << value.toQObject()->metaObject()->className() << "\" is not a number"; return false; } QMetaEnum metaEnum = QMetaEnum::fromType(); if (!metaEnum.isValid()) { qCDebug(scriptengine) << "Invalid QMetaEnum"; return false; } bool isValid = false; int enumInteger = static_cast(value.toInteger()); for(int i = 0; i < metaEnum.keyCount(); i++){ if (metaEnum.value(i) == enumInteger) { isValid = true; break; } } if (isValid) { enumValue = static_cast(enumInteger); return true; } else { qCDebug(scriptengine) << "ScriptValue has invalid value " << value.toInteger() << " for enum" << metaEnum.name(); return false; } } template int scriptRegisterSequenceMetaType(ScriptEngine* engine, T* = 0) { return scriptRegisterMetaType(engine); } #endif // hifi_ScriptEngineCast_h /// @}