Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

Commit fc5b0951 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

Precise handling of any/undefined/unknown values

parent 79e211c1
......@@ -27,7 +27,7 @@ detail. Moreover, W1 and RW2 require that we choose a careful compromise between
QTransmogrifier allows binding C++ `data` to a choice of:
* `sequence` of adjacent `data` `item`s
* `record` of named `data` `item`s
* `null` value (meaning no information available on `data`)
* `null` value (meaning information is irrelevant on `data`)
* Atomic values with a textual representation and optional binary ones:
- text (utf16/utf8 encodings)
- boolean (true/false)
......@@ -51,10 +51,11 @@ i((start))--"null()" --> x((end))
i((start))--"bind#lt;T>()"--> x((end))
i((start))--"sequence()" --> QSeq
i((start))--"record()" --> QRec
QSeq --"out()" --> x((end))
QRec --"out()" --> x((end))
QSeq --"item()" --> vs["QVal#lt;QSeq>"]
QRec --"item(name)" --> vr["QVal#lt;QRec>"]
QSeq --"out()" --> x((end))
QRec --"out()" --> x((end))
QSeq --"item()" --> vs["QVal#lt;QSeq>"]
QRec --"item(name)" --> vr["QVal#lt;QRec>"]
i((start))--"any()" --> x((end))
end
```
- Boxes (nested) represent possible states when traversing the data, the automaton is always in a single valid state
......
......@@ -69,7 +69,7 @@ enum SimpleValue : char {
False = 20,
True = 21,
Null = 22,
// Undefined = 23,
Undefined = 23,
// NextByteValue = 24,
// Next16BitFloat = 25,
Next32BitFloat = 26,
......@@ -120,7 +120,8 @@ protected:
bool tryRecord (quint32* cols=nullptr) { levels.push_back(cols);
if (Q_LIKELY(cols)) { putInteger (*cols , cbor::MapType ); }
else { putMajorValue(cbor::IndefiniteLength, cbor::MapType ); } return true; }
bool tryNull ( ) { putSimpleValue(cbor::Null ); return true; }
bool tryAny ( ) { putSimpleValue(cbor::Undefined); return true; }
bool tryNull ( ) { putSimpleValue(cbor::Null ); return true; }
bool tryBind ( QUtf8DataView u) { putInteger (quint64(u.size()), cbor::TextStringType); io->append(u.data(), u.size()); return true; }
bool tryBind ( QString&& s) { QUtf8Data u(s.toUtf8());
putInteger (quint64(u.size()), cbor::TextStringType); io->append(u.utf8()); return true; }
......@@ -189,9 +190,10 @@ public:
/**/ QSequence sequence(quint32* s=nullptr) { return QValueStatus(this).value().sequence(s); }
template<typename T> QValueStatus bind ( T&& t) { return QValueStatus(this).value().bind(std::forward<T>(t)); }
protected:
bool trySequence(quint32* =nullptr) { levels.push(Step( )); return true; }
bool tryRecord (quint32* =nullptr) { levels.push(Step(qBindExpectedItem)); return true; }
bool tryNull ( ) { set(QCborValue( )); return true; }
bool trySequence(quint32* =nullptr) { levels.push(Step( )); return true; }
bool tryRecord (quint32* =nullptr) { levels.push(Step(qBindExpectedItem )); return true; }
bool tryAny ( ) { set(QCborValue(QCborValue::Undefined)); return true; }
bool tryNull ( ) { set(QCborValue(nullptr )); return true; }
bool tryBind ( QUtf8DataView u) { set(QCborValue(QString::fromUtf8(u.data()))); return true; }
......@@ -249,6 +251,7 @@ public:
protected:
bool trySequence(quint32* =nullptr) { if (current().isArray ()) { steps.push(Step()); return true; } handleError(qBindExpectedSequence); return false; }
bool tryRecord (quint32* =nullptr) { if (current().isMap ()) { steps.push(Step()); return true; } handleError(qBindExpectedRecord ); return false; }
bool tryAny ( ) { if (current().isUndefined()) { return true; } handleError(qBindUnexpectedValue ); return false; }
bool tryNull ( ) { if (current().isNull ()) { return true; } handleError(qBindExpectedNull ); 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; }
......@@ -294,8 +297,10 @@ protected:
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); }
skipTag(); if (isMap () && enterContainer()) { levels.push(Level()); return true; } handleError(qBindExpectedRecord ); return false; }
bool tryAny ( ) { if (caching) { return caching->tryAny() && cacheOut(); }
skipTag(); return next(); }
bool tryNull ( ) { if (caching) { return caching->tryNull() && cacheOut(); }
skipTag(); if ((isNull() || isUndefined()) && next()) { return true; } handleError(qBindExpectedNull); return false; }
skipTag(); if (isNull() && 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 ( QString& s) { if (caching) { return caching->tryBind(s) && cacheOut(); }
skipTag(); if (isString()) {
......@@ -416,7 +421,6 @@ protected:
}
return leaveContainer(); }
bool tryAny() { return next(); }
bool isValid() const noexcept { return const_cast<QCborReader*>(this)->lastError()==QCborError::NoError; }
bool handleError(QIdentifierLiteral e, QString context = QString()) { return errorHandler ? errorHandler(e, QString("at index:%1 ").arg(currentOffset()).append(context)) : false; }
private:
......@@ -470,10 +474,11 @@ struct QTransmogrifier<QCborValue> {
if (j.isDouble ()) return v.bind(j.toDouble ());
if (j.isString ()) return v.bind(j.toString ());
if (j.isByteArray()) return v.bind(j.toByteArray());
if (j.isNull() || j.isUndefined() || j.isInvalid() || v->handleError(qBindExpectedValue)) return v.null();
if (j.isNull ()) return v.null();
if (j.isUndefined() || j.isInvalid() || v->handleError(qBindUnexpectedValue)) return v.any();
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.any(); }
}
static QValueStatus zap(QValue&& v, QCborValue& j) {
if (v->mode()==Write) {
......@@ -491,12 +496,12 @@ struct QTransmogrifier<QCborValue> {
j = QCborValue(double(u)); 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; }
r = v.null();
/**/ if ((r = v.null( ))) { j = QCborValue( nullptr ); v->setErrorHandler(suspended); return r; }
v->setErrorHandler(suspended);
if (r || v->handleError(qBindExpectedValue)) { j = QCborValue(); }
if ((r = v.any()) || v->handleError(qBindUnexpectedValue)) { j = QCborValue(); }
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.any(); }
}
};
......@@ -511,7 +516,7 @@ struct QTransmogrifier<QCborArray> {
}
return s;
}
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.any(); }
}
static QValueStatus zap(QValue&& v, QCborArray& j) {
if (v->mode()==Write) {
......@@ -527,7 +532,7 @@ struct QTransmogrifier<QCborArray> {
}
return s;
}
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.any(); }
}
};
......@@ -546,7 +551,7 @@ struct QTransmogrifier<QCborMap> {
}
return r;
}
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.any(); }
}
static QValueStatus zap(QValue&& v, QCborMap& j) {
if (v->mode()==Write) {
......@@ -562,6 +567,6 @@ struct QTransmogrifier<QCborMap> {
}
return s;
}
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.any(); }
}
};
......@@ -70,6 +70,7 @@ protected:
friend class QValueStatus;
bool trySequence(quint32* s=nullptr) { if (s) *io << *s; return true; }
bool tryRecord (quint32* s=nullptr) { if (s) *io << *s; return true; }
bool tryAny ( ) { return handleError(qBindUnexpectedValue); }
bool tryNull ( ) { *io << nullptr; return true; }
bool tryBind ( QUtf8DataView u) { QByteArray ba = QByteArray::fromRawData(u.data(), u.size()+int(sizeof('\0'))); return static_cast<QAbstractValue*>(this)->tryBind(ba); }
......
......@@ -67,7 +67,8 @@ protected:
friend class QJsonReader; //!< Calls methods below for out-of-order cachedItems
bool trySequence(quint32* s=nullptr) { Q_UNUSED(s); steps.push(Step( )); return true; }
bool tryRecord (quint32* s=nullptr) { Q_UNUSED(s); steps.push(Step(qBindExpectedItem)); return true; }
bool tryNull ( ) { set(QJsonValue( )); return true; }
bool tryAny ( ) { set(QJsonValue(QJsonValue::Undefined)); return true; }
bool tryNull ( ) { set(QJsonValue(QJsonValue::Null )); return true; }
bool tryBind ( QUtf8DataView u) { set(QJsonValue(u.data())); return true; }
bool tryBind ( bool&& b) { set(QJsonValue(b )); return true; }
bool tryBind ( double&& d) { set(QJsonValue(d )); return true; }
......@@ -120,7 +121,8 @@ public:
protected:
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 tryNull ( ) { if (current().isNull() || current().isUndefined()) { return true; } handleError(qBindExpectedNull ); return false; }
bool tryAny ( ) { if (current().isUndefined()) { return true; } handleError(qBindUnexpectedValue ); return false; }
bool tryNull ( ) { if (current().isNull() ) { return true; } handleError(qBindExpectedNull ); 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 ( bool& v) { if (current().isBool ()) { v = current().toBool (); return true; } handleError(qBindExpectedBoolean ); return false; }
......@@ -164,6 +166,7 @@ protected:
bool trySequence(quint32* s=nullptr) { Q_UNUSED(s); levels.push(Step{"","]"}); return putChar('['); }
bool tryRecord (quint32* s=nullptr) { Q_UNUSED(s); levels.push(Step{"","}"}); return putChar('{'); }
bool tryAny ( ) { return handleError(qBindUnexpectedValue) && write("undefined"); }
bool tryNull ( ) { return write("null"); }
bool tryBind ( QUtf8DataView u) { return putString(u.data(), u.size()); }
// JSON literals
......@@ -251,11 +254,12 @@ protected:
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); }
if (get('{', "[{\"ntf-0123456789.")) { levels.push(Step(-1,"}")); return true; } handleError(qBindExpectedRecord ); return false; }
bool tryAny ( ) { return next(",}]"); }
bool tryNull ( ) { if (caching) { return caching->tryNull() && cacheOut(); }
if (get('n', "[{\"ntf-0123456789.") &&
get('u', ",}]") &&
get('l', ",}]") &&
get('l', ",}]")) {
get('u') &&
get('l') &&
get('l')) {
return true;
} else { handleError(qBindExpectedNull); return false; } }
bool tryBind ( QUtf8Data& s) { if (caching) { return caching->tryBind(s) && cacheOut(); }
......@@ -268,16 +272,16 @@ protected:
bool tryBind ( QString& s) { QUtf8Data u; if (tryBind(u)) { s = QString(u.utf8()); return true; } return false; }
bool tryBind ( bool& b) { if (caching) { return caching->tryBind(b) && cacheOut(); }
if (get('t', "[{\"ntf-0123456789.") &&
get('r', "[{\"" ) &&
get('u', "[{\"" ) &&
get('e', "[{\"" )) { b=true;
get('r') &&
get('u') &&
get('e')) { b=true;
return true;
} else
if (get('f', "[{\"ntf-0123456789.") &&
get('a', "[{\"" ) &&
get('l', "[{\"" ) &&
get('s', "[{\"" ) &&
get('e', "[{\"" )) { b=false;
get('a') &&
get('l') &&
get('s') &&
get('e')) { b=false;
return true;
} else { handleError(qBindExpectedBoolean); return false; } }
bool tryBind ( float& n) { if (caching) { return caching->tryBind(n) && cacheOut(); }
......@@ -313,20 +317,25 @@ protected:
double d; if (tryBind(d)) { setErrorHandler(suspended); dst = QVariant(d+/*integer part consumed by one of*/u+l); return true; }
QUtf8Data s; if (tryBind(s)) { setErrorHandler(suspended);
QByteArray b;
if ( toByteArray(b, s)) { toVariant(dst, b); return true; }
dst = QVariant(QString::fromUtf8(s.utf8())) ; return true;
if (toByteArray(b, s)) {
toVariant(dst, b);
return true;
}
dst = QVariant(QString::fromUtf8(s.utf8()));
return true;
}
if (tryNull()) { setErrorHandler(suspended); dst = QVariant::fromValue(nullptr); return true; }
setErrorHandler(suspended);
if (!tryNull()) handleError(qBindExpectedValue);
dst = QVariant(); return true;
if (tryAny() || handleError(qBindUnexpectedValue)) { dst = QVariant(); return true; }
return false;
}
bool tryOut ( ) { if (caching) { bool out = caching->tryOut(); if (out) { cacheLevel--; cacheOut(); } return out; }
auto level = levels.pop();
while (get(',', level.end)) {
while (get(',', "}]")) {
tryAny();
}
return get(*level.end, "}"); }
return get(*level.end, "}]"); }
bool tryItem(QIdentifierLiteral u) { if (caching) { return caching->tryItem(u); }
QIdentifier s;
while (true) {
......@@ -521,10 +530,11 @@ struct QTransmogrifier<QJsonValue> {
if (j.isBool ()) return v.bind(j.toBool ());
if (j.isDouble()) return v.bind(j.toDouble());
if (j.isString()) return v.bind(j.toString());
if (j.isNull() || j.isUndefined() || v->handleError(qBindExpectedValue)) return v.null();
if (j.isNull ()) return v.null();
if (j.isUndefined() || v->handleError(qBindUnexpectedValue)) return v.any();
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.any(); }
}
static QValueStatus zap(QValue&& v, QJsonValue& j) {
if (v->mode()==Write) {
......@@ -533,19 +543,19 @@ struct QTransmogrifier<QJsonValue> {
else if (v->mode()==Read) {
QValueStatus r;
auto suspended = v->setErrorHandler();
QJsonArray a; if ((r = v.bind(a))) { j = a ; return r; }
QJsonObject o; if ((r = v.bind(o))) { j = o ; return r; }
QString t; if ((r = v.bind(t))) { j = QJsonValue( t) ; return r; }
bool b; if ((r = v.bind(b))) { j = QJsonValue( b) ; 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; }
double d; if ((r = v.bind(d))) { j = QJsonValue( d ); return r; }
r = v.null();
QJsonArray a; if ((r = v.bind(a))) { j = a ; v->setErrorHandler(suspended); return r; }
QJsonObject o; if ((r = v.bind(o))) { j = o ; v->setErrorHandler(suspended); return r; }
QString t; if ((r = v.bind(t))) { j = QJsonValue( t) ; v->setErrorHandler(suspended); return r; }
bool b; if ((r = v.bind(b))) { j = QJsonValue( b) ; v->setErrorHandler(suspended); return r; }
qint64 i; if ((r = v.bind(i))) { j = QJsonValue(double(i)); v->setErrorHandler(suspended); return r; }
quint64 u; if ((r = v.bind(u))) { j = QJsonValue(double(u)); v->setErrorHandler(suspended); return r; }
double d; if ((r = v.bind(d))) { j = QJsonValue( d ); v->setErrorHandler(suspended); return r; }
/**/ if ((r = v.null( ))) { j = QJsonValue( ); v->setErrorHandler(suspended); return r; }
v->setErrorHandler(suspended);
if (r || v->handleError(qBindExpectedValue)) { j = QJsonValue(); };
if (v->handleError(qBindUnexpectedValue)) { j = QJsonValue(QJsonValue::Undefined); }
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.any(); }
}
};
......@@ -560,7 +570,7 @@ struct QTransmogrifier<QJsonArray> {
}
return s;
}
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.any(); }
}
static QValueStatus zap(QValue&& v, QJsonArray& j) {
if (v->mode()==Write) {
......@@ -576,7 +586,7 @@ struct QTransmogrifier<QJsonArray> {
}
return s;
}
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.any(); }
}
};
......@@ -592,7 +602,7 @@ struct QTransmogrifier<QJsonObject> {
}
return s;
}
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.any(); }
}
static QValueStatus zap(QValue&& v, QJsonObject& j) {
if (v->mode()==Write) {
......@@ -608,6 +618,6 @@ struct QTransmogrifier<QJsonObject> {
}
return s;
}
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.any(); }
}
};
......@@ -102,6 +102,8 @@ protected:
}
}
virtual bool tryAny() { return true; }
using QAbstractValue::tryBind; // full overload set so that following overloads calls work (instead of calling themselves and overflowing the call stack)
virtual bool tryBind(const QUtf8Data& r) { QUtf8Data copy(r); return tryBind(std::move(copy)); }
......@@ -389,7 +391,8 @@ protected:
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() : write(QVariant()); }
virtual bool tryAny ( ) { return hidden() ? true : I<=d ? itemBind()->tryAny() : write(QVariant()); }
virtual bool tryNull( ) { return hidden() ? true : I<=d ? itemBind()->tryNull() : write(QVariant::fromValue(nullptr)); }
virtual bool tryBind( QString&& u) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(u)) : write(u ); }
virtual bool tryBind( bool&& b) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(b)) : write(b ); }
virtual bool tryBind( float&& f) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(f)) : write(f ); }
......@@ -595,7 +598,8 @@ protected:
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 () || !read().isValid(); }
virtual bool tryAny ( ) { return hidden() ? true : I<=d ? itemBind()->tryAny() : !read().isValid () ; }
virtual bool tryNull( ) { return hidden() ? true : I<=d ? itemBind()->tryNull() : read().isNull () ; }
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( float&& f) { return hidden() ? true : I<=d ? itemBind()->tryBind(std::move(f)) : qFuzzyCompare(f,read().toFloat ()); }
......
......@@ -65,7 +65,9 @@ protected:
bool tryBind (QUtf8DataView u) { settings->setValue(key(), QString::fromUtf8(u.data(), u.size())); return true; }
bool tryBind ( QStringView s) { settings->setValue(key(), s.toString() ); return true; }
bool tryBind ( QString&& s) { settings->setValue(key(), s ); return true; }
bool tryNull ( ) { settings->setValue(key(), QVariant() ); return true; }
bool tryAny () { settings->setValue(key(), QVariant() ); return true; }
bool tryNull() { settings->setValue(key(), QVariant::fromValue(nullptr)); return true; }
bool trySequence(quint32* =nullptr) { settings->beginGroup(key()); levels.push(Level( )); return true; }
bool tryRecord (quint32* =nullptr) { settings->beginGroup(key()); levels.push(Level(qBindExpectedItem)); return true; }
......@@ -129,7 +131,9 @@ protected:
bool trySequence(quint32* =nullptr) { if (levels.last().isGroup) { levels.push(Level( )); return true; } handleError(qBindExpectedSequence); return false; }
bool tryRecord (quint32* =nullptr) { if (levels.last().isGroup) { levels.push(Level(qBindExpectedItem)); return true; } handleError(qBindExpectedRecord ); return false; }
bool tryNull ( ) { if (settings->value(key()).isNull()) { return true; } handleError(qBindExpectedNull ); return false; }
bool tryAny () { if (!settings->value(key()).isValid()) { return true; } handleError(qBindUnexpectedValue); return false; }
bool tryNull() { if ( settings->value(key()).isNull ()) { return true; } handleError(qBindExpectedNull ); return false; }
bool tryItem(QIdentifier& k) { levels.last().key=k ; return true; }
bool tryItem( ) { levels.last().idx++ ; return true; }
......
#include "QValue.h"
QIdentifierLiteral qBindExpectedValue ("ExpectedValue" );
QIdentifierLiteral qBindUnexpectedValue ("UnexpectedValue" );
QIdentifierLiteral qBindExpectedItem ("ExpectedItem" );
QIdentifierLiteral qBindExpectedNull ("ExpectedNull" );
QIdentifierLiteral qBindExpectedSequence ("ExpectedSequence" );
......
......@@ -52,7 +52,7 @@
// //////////////////////////////////////////////////////////////////////////
// Standard error names
extern QIdentifierLiteral qBindExpectedValue;
extern QIdentifierLiteral qBindUnexpectedValue;
extern QIdentifierLiteral qBindExpectedItem;
extern QIdentifierLiteral qBindExpectedNull;
extern QIdentifierLiteral qBindExpectedSequence;
......@@ -155,7 +155,6 @@ struct QAbstractValue {
virtual bool trySequence(quint32* size=nullptr) = 0;
virtual bool tryRecord (quint32* size=nullptr) = 0;
virtual bool tryNull ( ) = 0;
virtual bool tryItem( ) = 0;
virtual bool tryItem(QIdentifier& n) = 0;
......@@ -220,7 +219,8 @@ struct QAbstractValue {
virtual bool tryBind( QByteArray&& r) = 0;
virtual bool tryBind( QVariant&& r) = 0;
virtual bool tryAny() { return tryNull(); }
virtual bool tryNull() = 0; //!< Null values are used where the information is irrelevant like in optional values or nullptr
virtual bool tryAny () = 0; //!< Any value is used where the information is unknown or undefined
//! \warning meta() is ignored by default and subject to various interpretation, so users should define or adopt existing meta data standards like XSD for sake of interoperability
virtual void _meta(QIdentifierLiteral&, QAsciiData&) {}
......@@ -308,7 +308,7 @@ template<typename T> struct QDefaultValue { T& value; const T& defaultValue; };
template<class T_> class QRec; //!< a Record data structure defined below
template<class T_> class QSeq; //!< a Sequence data structure defined below
template<class T_> class QVal; //!< a choice of sequence(), record(), null(), or any value with at least a textual representation and possibly binary ones
template<class T_> class QVal; //!< a choice of sequence(), record(), null(), or values with at least a textual representation and possibly binary ones
using QValue = QVal<QValueStatus>;
using QSequence = QSeq<QValueStatus>;
......@@ -604,7 +604,8 @@ struct QAbstractValueWriter : public QAbstractValue
return tryBind(binaryVariant);
}
if (src.isNull() || !src.isValid() || handleError(qBindExpectedValue)) return tryNull();
if (src.isNull()) return tryNull();
if (!src.isValid() || handleError(qBindUnexpectedValue)) return tryAny();
return false;
}
......@@ -639,6 +640,8 @@ struct QAbstractValueWriter : public QAbstractValue
virtual bool tryBind(const double& r) { double copy(r); return tryBind(std::move(copy)); }
virtual bool tryBind(const QByteArray& r) { QByteArray copy(r); return tryBind(std::move(copy)); }
virtual bool tryBind(const QVariant& r) { QVariant copy(r); return tryBind(std::move(copy)); }
virtual bool tryAny() { return tryNull(); }
};
//! Base QAbstractValue implementations with QValueMode::Read
......@@ -686,12 +689,10 @@ struct QAbstractValueReader : public QAbstractValue
QByteArray ba; if (tryBind(ba)) { toVariant(dst,ba); return true; }
QUtf8Data u8; if (tryBind(u8)) { dst = QVariant::fromValue(u8); return true; }
QString t; if (tryBind( t)) { dst = QVariant(t); return true; }
/**/ if (tryNull( )) { dst = QVariant::fromValue(nullptr); return true; }
setErrorHandler(suspended);
if (!tryNull() && handleError(QIdentifierLiteral("ExpectedOneOfBooleanDecimalBytesTextSequenceRecordNull"))) {
/**/ dst = QVariant( ); return true; }
else {
return false;
}
if (tryAny() || handleError(qBindUnexpectedValue)) { dst = QVariant(); return true; }
return false;
}
virtual bool tryBind(const QUtf8Data& k) { QUtf8Data r; if (tryBind(r) && k==r) return true; handleError(qBindExpectedConstant); return false; }
......@@ -726,22 +727,23 @@ struct QAbstractValueReader : public QAbstractValue
virtual bool tryBind( QByteArray&& k) { QByteArray r; if (tryBind(r) && k==r) return true; handleError(qBindExpectedConstant); return false; }
virtual bool tryBind( QVariant&& k) { QVariant r; if (tryBind(r) && k==r) return true; handleError(qBindExpectedConstant); return false; }
virtual bool tryAny() { auto suspended = setErrorHandler();
if ( (trySequence() && tryOut())
||(tryRecord () && tryOut())) {
return true;
}
bool b; // usually easier to check than types below
double d; // matches most used numbers more easily than types below
qint64 i; // matches most used integrals more easily than types below
quint64 u;
QVariant v;
QByteArray bytes;
QString s; // matches any type with usually less encoding work than QUtf8Data (which only captures efficiently utf-8 whereas QChar easily captures Latin1 in addition to ASCII)
bool bound = tryBind(b) || tryBind(d) || tryBind(i) || tryBind(u) || tryBind(v) || tryBind(bytes) || tryNull();
setErrorHandler(suspended);
return bound || handleError(qBindExpectedValue);
}
virtual bool tryAny() {
auto suspended = setErrorHandler();
if ( (trySequence() && tryOut())
||(tryRecord () && tryOut())) {
return true;
}
bool b; // usually easier to check than types below
double d; // matches most used numbers more easily than types below
qint64 i; // matches most used integrals more easily than types below
quint64 u;
QVariant v;
QByteArray bytes;
QString s; // matches any type with usually less encoding work than QUtf8Data (which only captures efficiently utf-8 whereas QChar easily captures Latin1 in addition to ASCII)
bool bound = tryBind(b) || tryBind(d) || tryBind(i) || tryBind(u) || tryBind(v) || tryBind(bytes) || tryNull();
setErrorHandler(suspended);
return bound || handleError(qBindUnexpectedValue);
}
QValueErrorHandler setErrorHandler(QValueErrorHandler newHandler = nullptr) { auto previousHandler = errorHandler; errorHandler = newHandler; return previousHandler; }
bool handleError(QIdentifierLiteral e, QString context = QString()) { return errorHandler ? errorHandler(e, context) : false; }
......@@ -906,10 +908,11 @@ QValueStatus qMetaZap(QValue&& v, T* t) {
// 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<QVariantMap >() ) r = i.bind(pv.value<QVariantMap >()); // TODO avoid interim data structure
else if (pv.isNull() || (!pv.isValid() && v->handleError(qBindExpectedValue))) r = i.null();
else if (pv.isNull() ) r = i.null();
else if (!pv.isValid() || v->handleError(qBindUnexpectedValue)) r = i.any();
}
}
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.any(); }
}
}
return r;
......@@ -951,7 +954,7 @@ struct QTransmogrifier<T, typename std::enable_if<std::is_unsigned<T>::value &&
else if (v->mode()==Read) {
quint64 u; auto r=v.bind(u); if (r) { t=u; } 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.any(); }
}
};
template<typename T>
......@@ -966,7 +969,7 @@ struct QTransmogrifier<T, typename std::enable_if<std::is_signed<T>::value && st
else if (v->mode()==Read) {
qint64 u; auto r=v.bind(u); if (r) { t=u; } 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.any(); }
}
};
......@@ -996,7 +999,7 @@ struct QTransmogrifier<T[Size]> {
}
return s;
}
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.any(); }
}
};
......@@ -1013,7 +1016,7 @@ struct QTransmogrifier<QVector<T>> {
}
return s;
}
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.any(); }
}
static QValueStatus zap(QValue&& v, QVector<T>& ts) {
if (v->mode()==Write) {
......@@ -1042,7 +1045,7 @@ struct QTransmogrifier<QVector<T>> {
}
return s;
}
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.any(); }
}
};
......@@ -1059,7 +1062,7 @@ struct QTransmogrifier<QList<T>> {
}
return s;
}