Specialize for QJson types in the QObject meta-call binding
authorKent Hansen <kent.hansen@nokia.com>
Tue, 24 Apr 2012 16:22:06 +0000 (18:22 +0200)
committerQt by Nokia <qt-info@nokia.com>
Thu, 26 Apr 2012 08:30:57 +0000 (10:30 +0200)
Avoid falling back to QVariant conversion; make the overload handling
consistent.

Also make the MaxSizeOf template helper class actually compute the
correct size needed for the argument storage.

Change-Id: I04afb378bd89743d542973cc3bb0ceb729b400d9
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
src/qml/qml/v8/qv8qobjectwrapper.cpp
tests/auto/qml/qqmlecmascript/testtypes.h
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp

index 176d4fb..70f10b2 100644 (file)
@@ -54,6 +54,8 @@
 #include <private/qqmlexpression_p.h>
 
 #include <QtQml/qjsvalue.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
 #include <QtCore/qjsonvalue.h>
 #include <QtCore/qvarlengtharray.h>
 #include <QtCore/qtimer.h>
@@ -124,14 +126,15 @@ public:
 
 namespace {
 
-template<typename A, typename B, typename C, typename D, typename E>
-class MaxSizeOf5 {
+template<typename A, typename B, typename C, typename D, typename E,
+         typename F, typename G, typename H>
+class MaxSizeOf8 {
     template<typename Z, typename X>
     struct SMax {
-        static const size_t Size = sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X);
+        char dummy[sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X)];
     };
 public:
-    static const size_t Size = SMax<A, SMax<B, SMax<C, SMax<D, E> > > >::Size;
+    static const size_t Size = sizeof(SMax<A, SMax<B, SMax<C, SMax<D, SMax<E, SMax<F, SMax<G, H> > > > > > >);
 };
 
 struct CallArgument {
@@ -155,11 +158,14 @@ private:
         bool boolValue;
         QObject *qobjectPtr;
 
-        char allocData[MaxSizeOf5<QVariant,
+        char allocData[MaxSizeOf8<QVariant,
                                 QString,
                                 QList<QObject *>,
                                 QJSValue,
-                                QQmlV8Handle>::Size];
+                                QQmlV8Handle,
+                                QJsonArray,
+                                QJsonObject,
+                                QJsonValue>::Size];
         qint64 q_for_alignment;
     };
 
@@ -170,6 +176,9 @@ private:
         QList<QObject *> *qlistPtr;
         QJSValue *qjsValuePtr;
         QQmlV8Handle *handlePtr;
+        QJsonArray *jsonArrayPtr;
+        QJsonObject *jsonObjectPtr;
+        QJsonValue *jsonValuePtr;
     };
 
     int type;
@@ -1588,6 +1597,8 @@ static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
         case QMetaType::Char:
         case QMetaType::UChar:
             return 6;
+        case QMetaType::QJsonValue:
+            return 5;
         default:
             return 10;
         }
@@ -1595,6 +1606,8 @@ static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
         switch (conversionType) {
         case QMetaType::QString:
             return 0;
+        case QMetaType::QJsonValue:
+            return 5;
         default:
             return 10;
         }
@@ -1602,6 +1615,8 @@ static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
         switch (conversionType) {
         case QMetaType::Bool:
             return 0;
+        case QMetaType::QJsonValue:
+            return 5;
         default:
             return 10;
         }
@@ -1625,6 +1640,8 @@ static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
         }
     } else if (actual->IsArray()) {
         switch (conversionType) {
+        case QMetaType::QJsonArray:
+            return 3;
         case QMetaType::QStringList:
         case QMetaType::QVariantList:
             return 5;
@@ -1635,6 +1652,7 @@ static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
         switch (conversionType) {
         case QMetaType::VoidStar:
         case QMetaType::QObjectStar:
+        case QMetaType::QJsonValue:
             return 0;
         default: {
             const char *typeName = QMetaType::typeName(conversionType);
@@ -1662,6 +1680,8 @@ static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
                 return 0;
             else
                 return 10;
+        } else if (conversionType == QMetaType::QJsonObject) {
+            return 5;
         } else {
             return 10;
         }
@@ -1983,6 +2003,12 @@ void CallArgument::cleanup()
         qjsValuePtr->~QJSValue();
     } else if (type == qMetaTypeId<QList<QObject *> >()) {
         qlistPtr->~QList<QObject *>();
+    }  else if (type == QMetaType::QJsonArray) {
+        jsonArrayPtr->~QJsonArray();
+    }  else if (type == QMetaType::QJsonObject) {
+        jsonObjectPtr->~QJsonObject();
+    }  else if (type == QMetaType::QJsonValue) {
+        jsonValuePtr->~QJsonValue();
     } 
 }
 
@@ -2023,6 +2049,15 @@ void CallArgument::initAsType(int callType)
     } else if (callType == qMetaTypeId<QQmlV8Handle>()) {
         type = callType;
         handlePtr = new (&allocData) QQmlV8Handle;
+    } else if (callType == QMetaType::QJsonArray) {
+        type = callType;
+        jsonArrayPtr = new (&allocData) QJsonArray();
+    } else if (callType == QMetaType::QJsonObject) {
+        type = callType;
+        jsonObjectPtr = new (&allocData) QJsonObject();
+    } else if (callType == QMetaType::QJsonValue) {
+        type = callType;
+        jsonValuePtr = new (&allocData) QJsonValue();
     } else if (callType == QMetaType::Void) {
         type = -1;
         qvariantPtr = new (&allocData) QVariant();
@@ -2080,6 +2115,15 @@ void CallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8::Val
     } else if (callType == qMetaTypeId<QQmlV8Handle>()) {
         handlePtr = new (&allocData) QQmlV8Handle(QQmlV8Handle::fromHandle(value));
         type = callType;
+    } else if (callType == QMetaType::QJsonArray) {
+        jsonArrayPtr = new (&allocData) QJsonArray(engine->jsonArrayFromJS(value));
+        type = callType;
+    } else if (callType == QMetaType::QJsonObject) {
+        jsonObjectPtr = new (&allocData) QJsonObject(engine->jsonObjectFromJS(value));
+        type = callType;
+    } else if (callType == QMetaType::QJsonValue) {
+        jsonValuePtr = new (&allocData) QJsonValue(engine->jsonValueFromJS(value));
+        type = callType;
     } else if (callType == QMetaType::Void) {
         *qvariantPtr = QVariant();
     } else {
@@ -2141,6 +2185,12 @@ v8::Handle<v8::Value> CallArgument::toValue(QV8Engine *engine)
         return array;
     } else if (type == qMetaTypeId<QQmlV8Handle>()) {
         return handlePtr->toHandle();
+    } else if (type == QMetaType::QJsonArray) {
+        return engine->jsonArrayToJS(*jsonArrayPtr);
+    } else if (type == QMetaType::QJsonObject) {
+        return engine->jsonObjectToJS(*jsonObjectPtr);
+    } else if (type == QMetaType::QJsonValue) {
+        return engine->jsonValueToJS(*jsonValuePtr);
     } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
         QVariant value = *qvariantPtr;
         v8::Handle<v8::Value> rv = engine->fromVariant(value);
index 502c65d..f39d5d9 100644 (file)
@@ -54,6 +54,9 @@
 #include <QtGui/QFont>
 #include <QtGui/QPixmap>
 #include <QtCore/qdatetime.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
 #include <QtQml/qjsvalue.h>
 #include <QtQml/qqmlscriptstring.h>
 #include <QtQml/qqmlcomponent.h>
@@ -678,6 +681,14 @@ public:
 
     Q_INVOKABLE void method_QVariant(QVariant a, QVariant b = QVariant()) { invoke(21); m_actuals << a << b; }
 
+    Q_INVOKABLE void method_QJsonObject(const QJsonObject &a) { invoke(22); m_actuals << QVariant::fromValue(a); }
+    Q_INVOKABLE void method_QJsonArray(const QJsonArray &a) { invoke(23); m_actuals << QVariant::fromValue(a); }
+    Q_INVOKABLE void method_QJsonValue(const QJsonValue &a) { invoke(24); m_actuals << QVariant::fromValue(a); }
+
+    Q_INVOKABLE void method_overload(const QJsonObject &a) { invoke(25); m_actuals << QVariant::fromValue(a); }
+    Q_INVOKABLE void method_overload(const QJsonArray &a) { invoke(26); m_actuals << QVariant::fromValue(a); }
+    Q_INVOKABLE void method_overload(const QJsonValue &a) { invoke(27); m_actuals << QVariant::fromValue(a); }
+
 private:
     friend class MyInvokableBaseObject;
     void invoke(int idx) { if (m_invoked != -1) m_invokedError = true; m_invoked = idx;}
index b66427e..4b913ef 100644 (file)
@@ -2607,6 +2607,97 @@ void tst_qqmlecmascript::callQtInvokables()
     QCOMPARE(o.actuals().count(), 2);
     QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
     QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_QJsonObject({foo:123})", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 22);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonObject>(o.actuals().at(0)), QJsonDocument::fromJson("{\"foo\":123}").object());
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_QJsonArray([123])", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 23);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonArray>(o.actuals().at(0)), QJsonDocument::fromJson("[123]").array());
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(123)", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 24);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonValue>(o.actuals().at(0)), QJsonValue(123));
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(42.35)", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 24);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonValue>(o.actuals().at(0)), QJsonValue(42.35));
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_QJsonValue('ciao')", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 24);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonValue>(o.actuals().at(0)), QJsonValue(QStringLiteral("ciao")));
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(true)", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 24);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonValue>(o.actuals().at(0)), QJsonValue(true));
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(false)", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 24);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonValue>(o.actuals().at(0)), QJsonValue(false));
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(null)", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 24);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonValue>(o.actuals().at(0)), QJsonValue(QJsonValue::Null));
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(undefined)", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 24);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonValue>(o.actuals().at(0)), QJsonValue(QJsonValue::Undefined));
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_overload({foo:123})", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 25);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonObject>(o.actuals().at(0)), QJsonDocument::fromJson("{\"foo\":123}").object());
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_overload([123])", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 26);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonArray>(o.actuals().at(0)), QJsonDocument::fromJson("[123]").array());
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_overload(null)", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 27);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonValue>(o.actuals().at(0)), QJsonValue(QJsonValue::Null));
+
+    o.reset();
+    QVERIFY(EVALUATE_VALUE("object.method_overload(undefined)", v8::Undefined()));
+    QCOMPARE(o.error(), false);
+    QCOMPARE(o.invoked(), 27);
+    QCOMPARE(o.actuals().count(), 1);
+    QCOMPARE(qvariant_cast<QJsonValue>(o.actuals().at(0)), QJsonValue(QJsonValue::Undefined));
 }
 
 // QTBUG-13047 (check that you can pass registered object types as args)