Commit 79abcda4 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère

Fixed QJsonReader cachelevel

More precise null handling including qBindExpectedValue for values that
are not null and not among the expecte values (say a QVariant other than
list/map and basic types...)
parent 51dab6dc
...@@ -294,10 +294,10 @@ protected: ...@@ -294,10 +294,10 @@ protected:
skipTag(); if (isArray () && enterContainer()) { levels.push(Level()); return true; } handleError(qBindExpectedSequence); return false; } skipTag(); if (isArray () && enterContainer()) { levels.push(Level()); return true; } handleError(qBindExpectedSequence); return false; }
bool tryRecord (quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->tryRecord(s); } bool tryRecord (quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->tryRecord(s); }
skipTag(); if (isMap () && enterContainer()) { levels.push(Level()); return true; } handleError(qBindExpectedRecord ); return false; } skipTag(); if (isMap () && enterContainer()) { levels.push(Level()); return true; } handleError(qBindExpectedRecord ); return false; }
bool tryNull ( ) { if (caching) { cacheLevel++; return caching->tryNull() && cacheOut(); } bool tryNull ( ) { if (caching) { return caching->tryNull() && cacheOut(); }
skipTag(); if (isNull () && next ()) { return true; } handleError(qBindExpectedNull ); return false; } skipTag(); if ((isNull() || isUndefined()) && next()) { return true; } handleError(qBindExpectedNull); return false; }
bool tryBind ( QUtf8Data& u) { QString s; if (tryBind(s)) { u = s.toUtf8(); return true; } return false; } bool tryBind ( QUtf8Data& u) { QString s; if (tryBind(s)) { u = s.toUtf8(); return true; } return false; }
bool tryBind ( QString& s) { if (caching) { cacheLevel++; return caching->tryBind(s) && cacheOut(); } bool tryBind ( QString& s) { if (caching) { return caching->tryBind(s) && cacheOut(); }
skipTag(); if (isString()) { skipTag(); if (isString()) {
s.resize(0); s.resize(0);
auto r = readString(); auto r = readString();
...@@ -313,7 +313,7 @@ protected: ...@@ -313,7 +313,7 @@ protected:
} }
return true; return true;
} else { handleError(qBindExpectedText); return false; } } } else { handleError(qBindExpectedText); return false; } }
bool tryBind ( QByteArray& s) { if (caching) { cacheLevel++; return caching->tryBind(s) && cacheOut(); } bool tryBind ( QByteArray& s) { if (caching) { return caching->tryBind(s) && cacheOut(); }
skipTag(); if (isByteArray()) { skipTag(); if (isByteArray()) {
s.resize(0); s.resize(0);
auto r = readByteArray(); auto r = readByteArray();
...@@ -329,12 +329,12 @@ protected: ...@@ -329,12 +329,12 @@ protected:
} }
return true; return true;
} else { handleError(qBindExpectedBytes); return false; } } } else { handleError(qBindExpectedBytes); return false; } }
bool tryBind ( bool& b) { if (caching) { cacheLevel++; return caching->tryBind(b) && cacheOut(); } bool tryBind ( bool& b) { if (caching) { return caching->tryBind(b) && cacheOut(); }
skipTag(); if (isBool()) { skipTag(); if (isBool()) {
b=toBool(); b=toBool();
return next(); return next();
} else { handleError(qBindExpectedBoolean); return false; } } } else { handleError(qBindExpectedBoolean); return false; } }
bool tryBind ( double& n) { if (caching) { cacheLevel++; return caching->tryBind(n) && cacheOut(); } bool tryBind ( double& n) { if (caching) { return caching->tryBind(n) && cacheOut(); }
return getNumber(n); } return getNumber(n); }
bool tryBind ( float& n) { double d; bool tryBind ( float& n) { double d;
if (!tryBind(d)) { return false; } if (!tryBind(d)) { return false; }
...@@ -342,12 +342,12 @@ protected: ...@@ -342,12 +342,12 @@ protected:
double(std::numeric_limits<float>::max()) <d) { handleError(qBindExpectedSmallerNumber); return false; } double(std::numeric_limits<float>::max()) <d) { handleError(qBindExpectedSmallerNumber); return false; }
n=float(d); return true; } n=float(d); return true; }
bool tryBind ( quint64& t) { if (caching) { cacheLevel++; return caching->tryBind(t) && cacheOut(); } bool tryBind ( quint64& t) { if (caching) { return caching->tryBind(t) && cacheOut(); }
quint64 i; bool neg; quint64 i; bool neg;
if (!getInteger(i,neg)) { handleError(qBindExpectedInteger ); return false; } if (!getInteger(i,neg)) { handleError(qBindExpectedInteger ); return false; }
if ( neg ) { handleError(qBindExpectedPositiveInteger); return false; } if ( neg ) { handleError(qBindExpectedPositiveInteger); return false; }
t=i; return true; } t=i; return true; }
bool tryBind ( qint64& t) { if (caching) { cacheLevel++; return caching->tryBind(t) && cacheOut(); } bool tryBind ( qint64& t) { if (caching) { return caching->tryBind(t) && cacheOut(); }
quint64 i; bool neg; quint64 i; bool neg;
if (!getInteger(i,neg)) { handleError(qBindExpectedInteger ); return false; } if (!getInteger(i,neg)) { handleError(qBindExpectedInteger ); return false; }
if ( neg ) { if (quint64(-std::numeric_limits<qint64>::min())<i) { handleError(qBindExpectedSmallerNumber); return false; } t=-qint64(i); return true; } if ( neg ) { if (quint64(-std::numeric_limits<qint64>::min())<i) { handleError(qBindExpectedSmallerNumber); return false; } t=-qint64(i); return true; }
...@@ -409,7 +409,7 @@ protected: ...@@ -409,7 +409,7 @@ protected:
return false; return false;
} }
return true; } return true; }
bool tryOut ( ) { if (caching) { return caching->tryOut() && cacheOut(); } bool tryOut ( ) { if (caching) { bool out = caching->tryOut(); if (out) { --cacheLevel; cacheOut(); } return out; }
levels.pop(); levels.pop();
while (hasNext()) { while (hasNext()) {
tryAny(); tryAny();
...@@ -433,9 +433,8 @@ private: ...@@ -433,9 +433,8 @@ private:
handleError(qBindExpectedInteger); return false; handleError(qBindExpectedInteger); return false;
} }
bool cacheOut() { Q_ASSERT(cacheLevel); bool cacheOut() { if (!cacheLevel) {
if (!--cacheLevel) { caching = nullptr;
caching=nullptr;
if (!device()->isSequential()) { if (!device()->isSequential()) {
device()->seek(cachingAfter); device()->seek(cachingAfter);
} }
...@@ -471,7 +470,8 @@ struct QTransmogrifier<QCborValue> { ...@@ -471,7 +470,8 @@ struct QTransmogrifier<QCborValue> {
if (j.isDouble ()) return v.bind(j.toDouble ()); if (j.isDouble ()) return v.bind(j.toDouble ());
if (j.isString ()) return v.bind(j.toString ()); if (j.isString ()) return v.bind(j.toString ());
if (j.isByteArray()) return v.bind(j.toByteArray()); if (j.isByteArray()) return v.bind(j.toByteArray());
return v.null(); if (j.isNull() || j.isUndefined() || j.isInvalid() || v->handleError(qBindExpectedValue)) return v.null();
return QValueStatus();
} }
else { Q_ASSERT_X(false, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); } else { Q_ASSERT_X(false, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); }
} }
...@@ -491,9 +491,9 @@ struct QTransmogrifier<QCborValue> { ...@@ -491,9 +491,9 @@ struct QTransmogrifier<QCborValue> {
j = QCborValue(double(u)); v->setErrorHandler(suspended); return r; } j = QCborValue(double(u)); v->setErrorHandler(suspended); return r; }
double d; if ((r = v.bind(d))) { j = QCborValue( d ); v->setErrorHandler(suspended); return r; } double d; if ((r = v.bind(d))) { j = QCborValue( d ); v->setErrorHandler(suspended); return r; }
QByteArray y; if ((r = v.bind(y))) { j = QCborValue( y ); v->setErrorHandler(suspended); return r; } QByteArray y; if ((r = v.bind(y))) { j = QCborValue( y ); v->setErrorHandler(suspended); return r; }
/**/ if ((r = v.null( ))) { j = QCborValue( ); v->setErrorHandler(suspended); return r; } r = v.null();
v->setErrorHandler(suspended); v->setErrorHandler(suspended);
v->handleError(qBindIgnoredItem); if (r || v->handleError(qBindExpectedValue)) { j = QCborValue(); }
return r; return r;
} }
else { Q_ASSERT_X(!v, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); } else { Q_ASSERT_X(!v, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); }
......
...@@ -120,7 +120,7 @@ public: ...@@ -120,7 +120,7 @@ public:
protected: protected:
bool trySequence(quint32* =nullptr) { if (current().isArray ()) { steps.push(Step()); return true; } handleError(qBindExpectedSequence); return false; } bool trySequence(quint32* =nullptr) { if (current().isArray ()) { steps.push(Step()); return true; } handleError(qBindExpectedSequence); return false; }
bool tryRecord (quint32* =nullptr) { if (current().isObject()) { steps.push(Step()); return true; } handleError(qBindExpectedRecord ); return false; } bool tryRecord (quint32* =nullptr) { if (current().isObject()) { steps.push(Step()); return true; } handleError(qBindExpectedRecord ); return false; }
bool tryNull ( ) { if (current().isNull ()) { return true; } handleError(qBindExpectedNull ); return false; } bool tryNull ( ) { if (current().isNull() || current().isUndefined()) { return true; } handleError(qBindExpectedNull ); return false; }
bool tryBind ( QUtf8Data& u) { QString s; if (tryBind(s) ) { u = s .toUtf8 (); return true; } return false; } bool tryBind ( QUtf8Data& u) { QString s; if (tryBind(s) ) { u = s .toUtf8 (); return true; } return false; }
bool tryBind ( QString& v) { if (current().isString()) { v = current().toString(); return true; } handleError(qBindExpectedText ); return false; } bool tryBind ( QString& v) { if (current().isString()) { v = current().toString(); return true; } handleError(qBindExpectedText ); return false; }
bool tryBind ( bool& v) { if (current().isBool ()) { v = current().toBool (); return true; } handleError(qBindExpectedBoolean ); return false; } bool tryBind ( bool& v) { if (current().isBool ()) { v = current().toBool (); return true; } handleError(qBindExpectedBoolean ); return false; }
...@@ -251,14 +251,14 @@ protected: ...@@ -251,14 +251,14 @@ protected:
if (get('[', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"]")); return true; } handleError(qBindExpectedSequence); return false; } if (get('[', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"]")); return true; } handleError(qBindExpectedSequence); return false; }
bool tryRecord (quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->tryRecord(s); } bool tryRecord (quint32* s=nullptr) { if (caching) { cacheLevel++; return caching->tryRecord(s); }
if (get('{', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"}")); return true; } handleError(qBindExpectedRecord ); return false; } if (get('{', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"}")); return true; } handleError(qBindExpectedRecord ); return false; }
bool tryNull ( ) { if (caching) { cacheLevel++; return caching->tryNull() && cacheOut(); } bool tryNull ( ) { if (caching) { return caching->tryNull() && cacheOut(); }
if (get('n', "[{\"ntf-0123456789.") && if (get('n', "[{\"ntf-0123456789.") &&
get('u', "[{\"" ) && get('u', ",}]") &&
get('l', "[{\"" ) && get('l', ",}]") &&
get('l', "[{\"" )) { get('l', ",}]")) {
return true; return true;
} else { handleError(qBindExpectedNull); return false; } } } else { handleError(qBindExpectedNull); return false; } }
bool tryBind ( QUtf8Data& s) { if (caching) { cacheLevel++; return caching->tryBind(s) && cacheOut(); } bool tryBind ( QUtf8Data& s) { if (caching) { return caching->tryBind(s) && cacheOut(); }
QByteArray u; QByteArray u;
if ( get('"', "[{\"ntf-0123456789.")) { u.resize(0); char c; if ( get('"', "[{\"ntf-0123456789.")) { u.resize(0); char c;
while ((c=getCharInString()) != '\0' ) { u.append(c); } while ((c=getCharInString()) != '\0' ) { u.append(c); }
...@@ -266,7 +266,7 @@ protected: ...@@ -266,7 +266,7 @@ protected:
return get('"'); return get('"');
} else { handleError(qBindExpectedText); return false; } } } else { handleError(qBindExpectedText); return false; } }
bool tryBind ( QString& s) { QUtf8Data u; if (tryBind(u)) { s = QString(u.utf8()); return true; } return false; } bool tryBind ( QString& s) { QUtf8Data u; if (tryBind(u)) { s = QString(u.utf8()); return true; } return false; }
bool tryBind ( bool& b) { if (caching) { cacheLevel++; return caching->tryBind(bool(b)) && cacheOut(); } bool tryBind ( bool& b) { if (caching) { return caching->tryBind(b) && cacheOut(); }
if (get('t', "[{\"ntf-0123456789.") && if (get('t', "[{\"ntf-0123456789.") &&
get('r', "[{\"" ) && get('r', "[{\"" ) &&
get('u', "[{\"" ) && get('u', "[{\"" ) &&
...@@ -280,28 +280,28 @@ protected: ...@@ -280,28 +280,28 @@ protected:
get('e', "[{\"" )) { b=false; get('e', "[{\"" )) { b=false;
return true; return true;
} else { handleError(qBindExpectedBoolean); return false; } } } else { handleError(qBindExpectedBoolean); return false; } }
bool tryBind ( float& n) { if (caching) { cacheLevel++; return caching->tryBind(double(n)) && cacheOut(); } bool tryBind ( float& n) { if (caching) { return caching->tryBind(n) && cacheOut(); }
if (getNumber()==None) return false; // already reported qBindExpectedDecimal if (getNumber()==None) return false; // already reported qBindExpectedDecimal
if (d<double( std::numeric_limits<float >::min())|| if (d<double( std::numeric_limits<float >::min())||
double( std::numeric_limits<float >::max())<d) { handleError(qBindExpectedSmallerNumber); return false; } double( std::numeric_limits<float >::max())<d) { handleError(qBindExpectedSmallerNumber); return false; }
n = float(d); cachedNumber=None; return true; } n = float(d); cachedNumber=None; return true; }
bool tryBind ( double& n) { if (caching) { cacheLevel++; return caching->tryBind(double(n)) && cacheOut(); } bool tryBind ( double& n) { if (caching) { return caching->tryBind(n) && cacheOut(); }
if (getNumber()==None) return false; // already reported qBindExpectedDecimal if (getNumber()==None) return false; // already reported qBindExpectedDecimal
n = d ; cachedNumber=None; return true; } n = d ; cachedNumber=None; return true; }
bool tryBind ( quint64& t) { if (caching) { cacheLevel++; return caching->tryBind(double(t)) && cacheOut(); } bool tryBind ( quint64& t) { if (caching) { return caching->tryBind(t) && cacheOut(); }
auto r=getNumber(); auto r=getNumber();
if (r==None) return false; // already reported qBindExpectedDecimal if (r==None) return false; // already reported qBindExpectedDecimal
if (r==FloatingPoint) { handleError(qBindExpectedInteger); return false; } if (r==FloatingPoint) { handleError(qBindExpectedInteger); return false; }
if (neg) { handleError(qBindExpectedPositiveInteger); return false; } if (neg) { handleError(qBindExpectedPositiveInteger); return false; }
t = i ; cachedNumber=None; return true; } t = i ; cachedNumber=None; return true; }
bool tryBind ( qint64& t) { if (caching) { cacheLevel++; return caching->tryBind(double(t)) && cacheOut(); } bool tryBind ( qint64& t) { if (caching) { return caching->tryBind(t) && cacheOut(); }
auto r=getNumber(); auto r=getNumber();
if (r==None) return false; // already reported qBindExpectedDecimal if (r==None) return false; // already reported qBindExpectedDecimal
if (r==FloatingPoint) { handleError(qBindExpectedInteger); return false; } if (r==FloatingPoint) { handleError(qBindExpectedInteger); return false; }
if (!neg && i<quint64( std::numeric_limits<qint64>::max())) { t = qint64(i); cachedNumber=None; return true; } if (!neg && i<quint64( std::numeric_limits<qint64>::max())) { t = qint64(i); cachedNumber=None; return true; }
if ( neg && i<quint64(-std::numeric_limits<qint64>::min())) { t = -qint64(i); cachedNumber=None; return true; } if ( neg && i<quint64(-std::numeric_limits<qint64>::min())) { t = -qint64(i); cachedNumber=None; return true; }
handleError(qBindExpectedSmallerNumber ); return false; } handleError(qBindExpectedSmallerNumber); return false; }
bool tryBind ( QVariant& dst) { bool tryBind ( QVariant& dst) { if (caching) { return caching->tryBind(dst) && cacheOut(); }
auto suspended = setErrorHandler(); auto suspended = setErrorHandler();
quint32 size=0; QIdentifier key; QVariant item; quint32 size=0; QIdentifier key; QVariant item;
...@@ -317,11 +317,11 @@ protected: ...@@ -317,11 +317,11 @@ protected:
dst = QVariant(QString::fromUtf8(s.utf8())) ; return true; dst = QVariant(QString::fromUtf8(s.utf8())) ; return true;
} }
setErrorHandler(suspended); setErrorHandler(suspended);
if (!tryNull()) handleError(QIdentifierLiteral("ExpectedOneOfBooleanDecimalBytesTextSequenceRecordNull")); if (!tryNull()) handleError(qBindExpectedValue);
dst = QVariant(); return true; dst = QVariant(); return true;
} }
bool tryOut ( ) { if (caching) { return caching->tryOut() && cacheOut(); } bool tryOut ( ) { if (caching) { bool out = caching->tryOut(); if (out) { cacheLevel--; cacheOut(); } return out; }
auto level = levels.pop(); auto level = levels.pop();
while (get(',', level.end)) { while (get(',', level.end)) {
tryAny(); tryAny();
...@@ -372,7 +372,7 @@ protected: ...@@ -372,7 +372,7 @@ protected:
return true; } return true; }
bool isValid() const noexcept { return io; } bool isValid() const noexcept { return io; }
bool handleError(QIdentifierLiteral e, QString context = QString()) { return errorHandler ? errorHandler(e, QString("at (%1,%2) ").arg(line).arg(column).append(context)) : false; } bool handleError(QIdentifierLiteral e, QString context = QString()) { return errorHandler ? errorHandler(e, QString("(%1:%2)").arg(line).arg(column).append(context)) : false; }
private: private:
CachedNumber getNumber() { CachedNumber getNumber() {
if (cachedNumber!=None) return cachedNumber; if (cachedNumber!=None) return cachedNumber;
...@@ -492,15 +492,16 @@ private: ...@@ -492,15 +492,16 @@ private:
CachedNumber cachedNumber = None; CachedNumber cachedNumber = None;
double d; quint64 i; bool neg; double d; quint64 i; bool neg;
bool cacheOut() { Q_ASSERT(cacheLevel); bool cacheOut() { if (!cacheLevel) {
if (!--cacheLevel) { caching=nullptr; } caching = nullptr;
}
return true; } return true; }
// Read/Write caching of out-of-order item keys // Read/Write caching of out-of-order item keys
quint8 cacheLevel = 0; quint8 cacheLevel = 0;
QJsonValue cachedValue ; //!< Only used AFTER --cacheLevel==1 QJsonValue cachedValue ; //!< Only used AFTER --cacheLevel==1
QJsonBuilder cacheWriter ; QJsonBuilder cacheWriter ;
QAbstractValue* caching = nullptr; //!< Only used when cacheLevel>=1 && key!=expectedKey QAbstractValue* caching = nullptr; //!< Only used when cacheLevel>=1 && key!=expectedKey
QJsonVisitor cacheReader ; //!< Only used as caching QJsonVisitor cacheReader ; //!< Only used as caching
}; };
...@@ -520,7 +521,8 @@ struct QTransmogrifier<QJsonValue> { ...@@ -520,7 +521,8 @@ struct QTransmogrifier<QJsonValue> {
if (j.isBool ()) return v.bind(j.toBool ()); if (j.isBool ()) return v.bind(j.toBool ());
if (j.isDouble()) return v.bind(j.toDouble()); if (j.isDouble()) return v.bind(j.toDouble());
if (j.isString()) return v.bind(j.toString()); if (j.isString()) return v.bind(j.toString());
return v.null(); if (j.isNull() || j.isUndefined() || v->handleError(qBindExpectedValue)) return v.null();
return QValueStatus();
} }
else { Q_ASSERT_X(false, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); } else { Q_ASSERT_X(false, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); }
} }
...@@ -538,9 +540,10 @@ struct QTransmogrifier<QJsonValue> { ...@@ -538,9 +540,10 @@ struct QTransmogrifier<QJsonValue> {
qint64 i; if ((r = v.bind(i))) { j = QJsonValue(double(i)); return r; } qint64 i; if ((r = v.bind(i))) { j = QJsonValue(double(i)); return r; }
quint64 u; if ((r = v.bind(u))) { j = QJsonValue(double(u)); return r; } quint64 u; if ((r = v.bind(u))) { j = QJsonValue(double(u)); return r; }
double d; if ((r = v.bind(d))) { j = QJsonValue( d ); return r; } double d; if ((r = v.bind(d))) { j = QJsonValue( d ); return r; }
r = v.null();
v->setErrorHandler(suspended); v->setErrorHandler(suspended);
if (!(r = v.null())) r.handleError(qBindExpectedValue); if (r || v->handleError(qBindExpectedValue)) { j = QJsonValue(); };
/**/ j = QJsonValue( ); return r; return r;
} }
else { Q_ASSERT_X(!v, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); } else { Q_ASSERT_X(!v, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); }
} }
......
...@@ -595,7 +595,7 @@ protected: ...@@ -595,7 +595,7 @@ protected:
using QAbstractValue::tryBind; // full overload set so that following overloads calls work (instead of calling themselves and overflowing the call stack) using QAbstractValue::tryBind; // full overload set so that following overloads calls work (instead of calling themselves and overflowing the call stack)
virtual bool tryNull( ) { return hidden() ? true : I<=d ? itemBind()->tryNull() : read().isNull () ; } virtual bool tryNull( ) { return hidden() ? true : I<=d ? itemBind()->tryNull() : read().isNull () || !read().isValid(); }
virtual bool tryBind( QString&& u) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(u)) : u==read().toString() ; } virtual bool tryBind( QString&& u) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(u)) : u==read().toString() ; }
virtual bool tryBind( bool&& b) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(b)) : b==read().toBool () ; } virtual bool tryBind( bool&& b) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(b)) : b==read().toBool () ; }
virtual bool tryBind( float&& f) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(f)) : qFuzzyCompare(f,read().toFloat ()); } virtual bool tryBind( float&& f) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(f)) : qFuzzyCompare(f,read().toFloat ()); }
......
...@@ -348,12 +348,12 @@ public: ...@@ -348,12 +348,12 @@ public:
/**/ T_ bind ( QLatin1String l) { return outer->tryBind (l) ? std::move(outer) : T_ (); } /**/ T_ bind ( QLatin1String l) { return outer->tryBind (l) ? std::move(outer) : T_ (); }
/**/ T_ bind ( QStringView u) { return outer->tryBind (u) ? std::move(outer) : T_ (); } /**/ T_ bind ( QStringView u) { return outer->tryBind (u) ? std::move(outer) : T_ (); }
template<typename T> T_ bind ( T&& t) { return outer->tryBind(std::forward <T>(t )) ? std::move(outer) : T_(); } template<typename T> T_ bind( T&& t) { return outer->tryBind(std::forward <T>(t )) ? std::move(outer) : T_(); }
template<typename T> T_ bind (T& t, T&& defaultT) { return outer->tryBind(QDefaultValue<T>{t,defaultT}) ? std::move(outer) : T_(); } template<typename T> T_ bind(T& t, T&& defaultT) { return outer->tryBind(QDefaultValue<T>{t,defaultT}) ? std::move(outer) : T_(); }
// Custom bind support // Custom bind support
/**/ T_ with ( QValLambda customBind) { return customBind( std::move(unsafeThis())) ? std::move(outer) : T_(); } /**/ T_ with( QValLambda customBind) { return customBind( std::move(unsafeThis())) ? std::move(outer) : T_(); }
template<typename T> T_ with (T& t, QValFunction<T> customBind) { return customBind(t, std::move(unsafeThis())) ? std::move(outer) : T_(); } template<typename T> T_ with(T& t, QValFunction<T> customBind) { return customBind(t, std::move(unsafeThis())) ? std::move(outer) : T_(); }
// Literal metadata support // Literal metadata support
QVal<T_> meta(const char* n, const char* m) { return meta(QIdentifierLiteral(n),QAsciiData(m)); } QVal<T_> meta(const char* n, const char* m) { return meta(QIdentifierLiteral(n),QAsciiData(m)); }
...@@ -385,7 +385,7 @@ public: ...@@ -385,7 +385,7 @@ public:
QValueStatus* operator->() noexcept { return outer.operator ->(); } QValueStatus* operator->() noexcept { return outer.operator ->(); }
operator QValueStatus() { return out(); /* calls T_::operator QValueStatus() if T_ != QValueStatus */ } operator QValueStatus() { return out(); /* calls T_::operator QValueStatus() if T_ != QValueStatus */ }
/**/ T_ out() { return outer-> tryOut() ? std::move(outer) : T_ (); } /**/ T_ out() { return outer-> tryOut() ? std::move(outer) : T_ (); }
QVal<QSeq<T_>> item() { return outer->tryItem() ? QVal<QSeq<T_>>(std::move(*this)) : QVal<QSeq<T_>>(); } QVal<QSeq<T_>> item() { return outer->tryItem() ? QVal<QSeq<T_>>(std::move(*this)) : QVal<QSeq<T_>>(); }
// Shortcuts // Shortcuts
...@@ -574,7 +574,6 @@ struct QAbstractValueWriter : public QAbstractValue ...@@ -574,7 +574,6 @@ struct QAbstractValueWriter : public QAbstractValue
} }
return tryOut(); return tryOut();
} }
if (src.isNull() ) return tryNull();
if (src.userType() // TODO src.type if QUtf8Data becomes a Qt type if (src.userType() // TODO src.type if QUtf8Data becomes a Qt type
==qMetaTypeId<QUtf8Data>()) return tryBind(src.value< QUtf8Data>()); ==qMetaTypeId<QUtf8Data>()) return tryBind(src.value< QUtf8Data>());
if (src.type()==QVariant::String ) return tryBind(src.value< QString>()); if (src.type()==QVariant::String ) return tryBind(src.value< QString>());
...@@ -605,7 +604,8 @@ struct QAbstractValueWriter : public QAbstractValue ...@@ -605,7 +604,8 @@ struct QAbstractValueWriter : public QAbstractValue
return tryBind(binaryVariant); return tryBind(binaryVariant);
} }
return tryNull(); if (src.isNull() || !src.isValid() || handleError(qBindExpectedValue)) return tryNull();
return false;
} }
virtual bool tryBind( QUtf8Data& r) { QUtf8Data copy(r); return tryBind(std::move(copy)); } virtual bool tryBind( QUtf8Data& r) { QUtf8Data copy(r); return tryBind(std::move(copy)); }
...@@ -846,7 +846,7 @@ QSeq<T_> QSeq<T_>::forEach(Ts& ts, ...@@ -846,7 +846,7 @@ QSeq<T_> QSeq<T_>::forEach(Ts& ts,
// For Q_DEFINE_ZAP_WITH_METAOBJECT below // For Q_DEFINE_ZAP_WITH_METAOBJECT below
template<class T> template<class T>
QValueStatus qzap(QValue&& v, T* t) { QValueStatus qMetaZap(QValue&& v, T* t) {
auto rw = v->mode(); auto rw = v->mode();
auto mo = T::staticMetaObject; auto mo = T::staticMetaObject;
auto r = v.meta(qmName,QAsciiData(mo.className())).record(); auto r = v.meta(qmName,QAsciiData(mo.className())).record();
...@@ -876,17 +876,16 @@ QValueStatus qzap(QValue&& v, T* t) { ...@@ -876,17 +876,16 @@ QValueStatus qzap(QValue&& v, T* t) {
if (!pv.isValid() && !v->handleError(qBindIgnoredItem)) { if (!pv.isValid() && !v->handleError(qBindIgnoredItem)) {
return QValueStatus(); return QValueStatus();
} }
else if (!pv.isNull()) { else {
QIdentifier id(p.name()); QIdentifier id(p.name());
auto i = r.item(id); auto i = r.item(id);
if (p.isEnumType()) { if (pv.isValid() && p.isEnumType()) {
pv.convert(QVariant::Int); pv.convert(QVariant::Int);
i = i.meta(qmName, p.isFlagType() ? i = i.meta(qmName, p.isFlagType() ?
QAsciiData(p.enumerator().valueToKeys(pv.value<int>())) : QAsciiData(p.enumerator().valueToKeys(pv.value<int>())) :
QAsciiData(p.enumerator().valueToKey (pv.value<int>()))); QAsciiData(p.enumerator().valueToKey (pv.value<int>())));
} }
if (pv.isNull() ) r = i.null(); if (pv.userType()==qMetaTypeId<QUtf8Data>() // TODO pv.type if QUtf8Data becomes a Qt type
else if (pv.userType()==qMetaTypeId<QUtf8Data>() // TODO pv.type if QUtf8Data becomes a Qt type
) r = i.bind(pv.value< QUtf8Data>()); ) r = i.bind(pv.value< QUtf8Data>());
else if (pv.type()==QVariant::String ) r = i.bind(pv.value< QString>()); else if (pv.type()==QVariant::String ) r = i.bind(pv.value< QString>());
else if (pv.type()==QVariant::Char ) r = i.bind(pv. toString()); else if (pv.type()==QVariant::Char ) r = i.bind(pv. toString());
...@@ -907,7 +906,7 @@ QValueStatus qzap(QValue&& v, T* t) { ...@@ -907,7 +906,7 @@ QValueStatus qzap(QValue&& v, T* t) {
// See QT_FOR_EACH_STATIC_PRIMITIVE_TYPE in qmetatype.h // See QT_FOR_EACH_STATIC_PRIMITIVE_TYPE in qmetatype.h
else if (pv.canConvert<QVariantList>() ) r = i.bind(pv.value<QVariantList>()); // TODO avoid interim data structure else if (pv.canConvert<QVariantList>() ) r = i.bind(pv.value<QVariantList>()); // TODO avoid interim data structure
else if (pv.canConvert<QVariantMap >() ) r = i.bind(pv.value<QVariantMap >()); // TODO avoid interim data structure else if (pv.canConvert<QVariantMap >() ) r = i.bind(pv.value<QVariantMap >()); // TODO avoid interim data structure
else r = i.bind(pv); // FIXME remove one QVariant level as in QAbstractValueWriter::tryBind(QVariant&&) else if (pv.isNull() || (!pv.isValid() && v->handleError(qBindExpectedValue))) r = i.null();
} }
} }
else { Q_ASSERT_X(!v, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); } else { Q_ASSERT_X(!v, Q_FUNC_INFO, "Unsupported v->mode()"); return v.null(); }
...@@ -917,21 +916,23 @@ QValueStatus qzap(QValue&& v, T* t) { ...@@ -917,21 +916,23 @@ QValueStatus qzap(QValue&& v, T* t) {
} }
//! Default bind(QValue&&) based on static QMetaObject reflection //! Default bind(QValue&&) based on static QMetaObject reflection
#define Q_DEFINE_ZAP_WITH_METAOBJECT(Class) QValueStatus zap(QValue&& v) { return qzap<Class>(std::move(v), this); } #define Q_DEFINE_ZAP_WITH_METAOBJECT(Class) QValueStatus zap(QValue&& v) { return qMetaZap<Class>(std::move(v), this); }
template<typename T> template<typename T>
struct QTransmogrifier<QDefaultValue<T>> { struct QTransmogrifier<QDefaultValue<T>> {
static QValueStatus zap(QValue&& v, QDefaultValue<T>&& t) { static QValueStatus zap(QValue&& v, QDefaultValue<T>&& t) {
if (v->mode()==Read) { if (v->mode()!=Read) {
return v.bind(t.value);
} else {
auto suspended = v->setErrorHandler(); auto suspended = v->setErrorHandler();
auto r=v.null(); auto r = v.bind(t.value);
v->setErrorHandler(suspended); v->setErrorHandler(suspended);
if (r) { if (!r) {
t.value = t.defaultValue; t.value = t.defaultValue;
return r; return v.null();
} }
return r;
} }
return v.bind(t.value);
} }
static QValueStatus zap(QValue&& v, QDefaultValue<T>& t) { static QValueStatus zap(QValue&& v, QDefaultValue<T>& t) {
return bind(std::move(v),std::move(t)); return bind(std::move(v),std::move(t));
...@@ -1165,29 +1166,31 @@ struct QTransmogrifier<QValue> { ...@@ -1165,29 +1166,31 @@ struct QTransmogrifier<QValue> {
/**/ dstRec.out(); /**/ dstRec.out();
return srcRec.out(); return srcRec.out();
} }
if ( (srcRes = src.null())) { QUtf8Data u; if ((srcRes = src.bind( u))) { dst.bind( u); src->setErrorHandler(suspended); return srcRes; } //! \remark QUtf8Data has common valus with QString but is more precise and efficient
return dst.null(); QString t; if ((srcRes = src.bind( t))) { dst.bind( t); src->setErrorHandler(suspended); return srcRes; }
}
QUtf8Data u; if ((srcRes = src.bind( u))) { dst.bind( u); return srcRes; } //! \remark QUtf8Data has common valus with QString but is more precise and efficient
QString t; if ((srcRes = src.bind( t))) { dst.bind( t); return srcRes; }
// Explicitely handled types (not value text representation convertible to those types // Explicitely handled types (not value text representation convertible to those types
QByteArray a; if ((srcRes = src.bind( a))) { dst.bind( a); return srcRes; } QByteArray a; if ((srcRes = src.bind( a))) { dst.bind( a); src->setErrorHandler(suspended); return srcRes; }
bool b; if ((srcRes = src.bind( b))) { dst.bind( b); return srcRes; } bool b; if ((srcRes = src.bind( b))) { dst.bind( b); src->setErrorHandler(suspended); return srcRes; }
quint8 u8; if ((srcRes = src.bind( u8))) { dst.bind( u8); return srcRes; } //! \remark quint8 has common values with qint8 but is preferred for convenience and static guarantees (no negative values) quint8 u8; if ((srcRes = src.bind( u8))) { dst.bind( u8); src->setErrorHandler(suspended); return srcRes; } //! \remark quint8 has common values with qint8 but is preferred for convenience and static guarantees (no negative values)
qint8 l8; if ((srcRes = src.bind( l8))) { dst.bind( l8); return srcRes; } qint8 l8; if ((srcRes = src.bind( l8))) { dst.bind( l8); src->setErrorHandler(suspended); return srcRes; }
quint16 u16; if ((srcRes = src.bind(u16))) { dst.bind(u16); return srcRes; } //! \remark Bigger numeric types can only be handled if QAbstractValue refuses to lose sign or leading digits quint16 u16; if ((srcRes = src.bind(u16))) { dst.bind(u16); src->setErrorHandler(suspended); return srcRes; } //! \remark Bigger numeric types can only be handled if QAbstractValue refuses to lose sign or leading digits
qint16 l16; if ((srcRes = src.bind(l16))) { dst.bind(l16); return srcRes; } qint16 l16; if ((srcRes = src.bind(l16))) { dst.bind(l16); src->setErrorHandler(suspended); return srcRes; }
quint32 u32; if ((srcRes = src.bind(u32))) { dst.bind(u32); return srcRes; } quint32 u32; if ((srcRes = src.bind(u32))) { dst.bind(u32); src->setErrorHandler(suspended); return srcRes; }
qint32 l32; if ((srcRes = src.bind(l32))) { dst.bind(l32); return srcRes; } qint32 l32; if ((srcRes = src.bind(l32))) { dst.bind(l32); src->setErrorHandler(suspended); return srcRes; }
quint64 u64; if ((srcRes = src.bind(u64))) { dst.bind(u64); return srcRes; } quint64 u64; if ((srcRes = src.bind(u64))) { dst.bind(u64); src->setErrorHandler(suspended); return srcRes; }
qint64 l64; if ((srcRes = src.bind(l64))) { dst.bind(l64); return srcRes; } qint64 l64; if ((srcRes = src.bind(l64))) { dst.bind(l64); src->setErrorHandler(suspended); return srcRes; }
float f