aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-11-15 10:13:09 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-11-15 14:26:17 +0100
commit7b29ed6f64a300d4d714371c2872fcba344beebd (patch)
treed2e83316030d03a05317958e22770bb784ffcbe0 /src
parentd9d247746423f6a9f1f36aa9be14fad1edcd6616 (diff)
QJSEngine: Provide a method to coerce values in JS fashion
JavaScript has its own type coercion rules. We already have a methods that coerce QVariants, QJSValues and QJSManagedValues to specific types. The new method is a generalization of all of those and can coerce everything to everything (as far as JavaScript can). Change-Id: I9b6877fb40f67b6f2354781bbd4cf18cf996c7b0 Reviewed-by: Sami Shalayel <sami.shalayel@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/jsapi/qjsengine.cpp31
-rw-r--r--src/qml/jsapi/qjsengine.h73
-rw-r--r--src/qml/jsruntime/qv4engine_p.h7
3 files changed, 99 insertions, 12 deletions
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 61042607c9..98df83fd99 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -833,7 +833,7 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
return convertV2(value, QMetaType(type), ptr);
}
-static bool convertString(const QString &string, QMetaType metaType, void *ptr)
+bool QJSEngine::convertString(const QString &string, QMetaType metaType, void *ptr)
{
// have a string based value without engine. Do conversion manually
if (metaType == QMetaType::fromType<bool>()) {
@@ -906,20 +906,24 @@ bool QJSEngine::convertV2(const QJSValue &value, QMetaType metaType, void *ptr)
bool QJSEngine::convertVariant(const QVariant &value, QMetaType metaType, void *ptr)
{
- if (value.metaType() == QMetaType::fromType<QString>())
- return convertString(value.toString(), metaType, ptr);
-
// TODO: We could probably avoid creating a QV4::Value in many cases, but we'd have to
// duplicate much of metaTypeFromJS and some methods of QV4::Value itself here.
return QV4::ExecutionEngine::metaTypeFromJS(handle()->fromVariant(value), metaType, ptr);
}
+bool QJSEngine::convertMetaType(QMetaType fromType, const void *from, QMetaType toType, void *to)
+{
+ // TODO: We could probably avoid creating a QV4::Value in many cases, but we'd have to
+ // duplicate much of metaTypeFromJS and some methods of QV4::Value itself here.
+ return QV4::ExecutionEngine::metaTypeFromJS(handle()->fromData(fromType, from), toType, to);
+}
+
/*! \fn template <typename T> QJSValue QJSEngine::toScriptValue(const T &value)
Creates a QJSValue with the given \a value.
This works with any type \c{T} that has a \c{QMetaType}.
- \sa fromScriptValue()
+ \sa fromScriptValue(), coerceValue()
*/
/*! \fn template <typename T> T QJSEngine::fromScriptValue(const QJSValue &value)
@@ -927,7 +931,7 @@ bool QJSEngine::convertVariant(const QVariant &value, QMetaType metaType, void *
Returns the given \a value converted to the template type \c{T}.
This works with any type \c{T} that has a \c{QMetaType}.
- \sa toScriptValue()
+ \sa toScriptValue(), coerceValue()
*/
/*! \fn template <typename T> T QJSEngine::fromVariant(const QVariant &value)
@@ -939,7 +943,20 @@ bool QJSEngine::convertVariant(const QVariant &value, QMetaType metaType, void *
conversions between JavaScript-equivalent types that are not
performed by qvariant_cast by default.
- \sa fromScriptValue() qvariant_cast()
+ \sa coerceValue(), fromScriptValue(), qvariant_cast()
+*/
+
+/*! \fn template <typename From, typename To> T QJSEngine::coerceValue(const From &from)
+
+ Returns the given \a from converted to the template type \c{To}.
+ This works with any type \c{T} that has a \c{QMetaType}. The
+ conversion is done in JavaScript semantics. Those differ from
+ qvariant_cast's semantics. There are a number of implicit
+ conversions between JavaScript-equivalent types that are not
+ performed by qvariant_cast by default. This method is a generalization of
+ all the other conversion methods in this class.
+
+ \sa fromVariant(), qvariant_cast(), fromScriptValue(), toScriptValue()
*/
/*!
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 74f8b2892f..1dde093a01 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -83,8 +83,9 @@ public:
if constexpr (std::is_same_v<T, QVariant>)
return value;
+ const QMetaType sourceType = value.metaType();
const QMetaType targetType = QMetaType::fromType<T>();
- if (value.metaType() == targetType)
+ if (sourceType == targetType)
return *reinterpret_cast<const T *>(value.constData());
if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) {
@@ -94,16 +95,81 @@ public:
return *reinterpret_cast<const nonConstT *>(value.constData());
}
+ if constexpr (std::is_same_v<T, QJSValue>)
+ return toScriptValue(value);
+
+ if constexpr (std::is_same_v<T, QJSManagedValue>)
+ return toManagedValue(value);
+
+ if (sourceType == QMetaType::fromType<QJSValue>())
+ return fromScriptValue<T>(*reinterpret_cast<const QJSValue *>(value.constData()));
+
+ if (sourceType == QMetaType::fromType<QJSManagedValue>()) {
+ return fromManagedValue<T>(
+ *reinterpret_cast<const QJSManagedValue *>(value.constData()));
+ }
+
+
{
T t{};
- if (convertVariant(value, targetType, &t))
+ if (value.metaType() == QMetaType::fromType<QString>()) {
+ if (convertString(value.toString(), targetType, &t))
+ return t;
+ } else if (convertVariant(value, targetType, &t)) {
return t;
+ }
QMetaType::convert(value.metaType(), value.constData(), targetType, &t);
return t;
}
}
+ template<typename From, typename To>
+ inline To coerceValue(const From &from)
+ {
+ if constexpr (std::is_same_v<From, To>)
+ return from;
+
+ if constexpr (std::is_same_v<To, QJSValue>)
+ return toScriptValue(from);
+
+ if constexpr (std::is_same_v<From, QJSValue>)
+ return fromScriptValue<To>(from);
+
+ if constexpr (std::is_same_v<To, QJSManagedValue>)
+ return toManagedValue(from);
+
+ if constexpr (std::is_same_v<From, QJSManagedValue>)
+ return fromManagedValue<To>(from);
+
+ if constexpr (std::is_same_v<From, QVariant>)
+ return fromVariant<To>(from);
+
+ if constexpr (std::is_same_v<To, QVariant>)
+ return QVariant::fromValue(from);
+
+ if constexpr (std::is_same_v<To, std::remove_const_t<std::remove_pointer_t<To>> const *>) {
+ using nonConstTo = std::remove_const_t<std::remove_pointer_t<To>> *;
+ if constexpr (std::is_same_v<From, nonConstTo>)
+ return from;
+ }
+
+ {
+ const QMetaType sourceType = QMetaType::fromType<From>();
+ const QMetaType targetType = QMetaType::fromType<To>();
+ To to{};
+ if constexpr (std::is_same_v<From, QString>) {
+ if (convertString(from, targetType, &to))
+ return to;
+ } else if (convertMetaType(sourceType, &from, targetType, &to)) {
+ return to;
+ }
+
+ QMetaType::convert(sourceType, &from, targetType, &to);
+ return to;
+ }
+ }
+
void collectGarbage();
enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
@@ -148,7 +214,10 @@ private:
static bool convertManaged(const QJSManagedValue &value, QMetaType type, void *ptr);
static bool convertV2(const QJSValue &value, int type, void *ptr);
static bool convertV2(const QJSValue &value, QMetaType metaType, void *ptr);
+ static bool convertString(const QString &string, QMetaType metaType, void *ptr);
+
bool convertVariant(const QVariant &value, QMetaType metaType, void *ptr);
+ bool convertMetaType(QMetaType fromType, const void *from, QMetaType toType, void *to);
template<typename T>
friend inline T qjsvalue_cast(const QJSValue &);
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 067ddc7243..5434f55548 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -740,13 +740,14 @@ public:
QV4::ReturnedValue callInContext(QV4::Function *function, QObject *self,
QV4::ExecutionContext *ctxt, int argc, const QV4::Value *argv);
+ QV4::ReturnedValue fromData(
+ QMetaType type, const void *ptr,
+ Heap::Object *parent = nullptr, int property = -1, uint flags = 0);
+
private:
template<int Frames>
friend struct ExecutionEngineCallDepthRecorder;
- QV4::ReturnedValue fromData(
- QMetaType type, const void *ptr,
- Heap::Object *parent = nullptr, int property = -1, uint flags = 0);
static void initializeStaticMembers();
static int s_maxCallDepth;