Commit 38d6c5c1 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère

Added QSuspendedValueErrorHandler to make suspend/resume more robust

Added QValue::setIsVariant to automate suspend/resume, error reporting
and error recovery using tryAny()
Fixed QVal::any() that missed resumeErrorHandler
Fixed QCborReader::tryBind(quint64) that consumed negative integers
Fixed handleError(qBindUnexpectedValue) to be more consistent
Removed unused and untested move operations for some QAbstractValue
implementations
parent 833b8baf
#-------------------------------------------------
#
# Project created by QtCreator 2018-06-12T22:10:15
#
#-------------------------------------------------
QT += widgets
TARGET = QBind
CONFIG += c++11 console
CONFIG -= app_bundle
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# C++17 allows replacing 'if /*constexpr*/' with 'if constexpr' with little performance improvement
#gcc:QMAKE_CXXFLAGS += -std=c++1z
#msvc:QMAKE_CXXFLAGS += /std=c++17
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
gcc:QMAKE_CXXFLAGS += -ftemplate-backtrace-limit=0
#PROTO_FILE = persons.proto
#protoc.output = $${OUT_PWD}/${QMAKE_FILE_IN_BASE}.pb.cc
#protoc.variable_out = GENERATED_SOURCES
#protoc.input = PROTO_FILE
#win32 {
# PROTO_PATH = /path/to/protobuf-3.7.1-msvc2019
# DEFINES += PROTOBUF_USE_DLLS
# protoc.commands = $${PROTO_PATH}/bin/protoc -I=$$relative_path($${PWD}, $${OUT_PWD}) --cpp_out=. ${QMAKE_FILE_NAME}
# INCLUDEPATH += $${PROTO_PATH}/include
# DEPENDPATH += $${PROTO_PATH}/include
# LIBS += -L$${PROTO_PATH}/lib -llibprotobuf
#}
#QMAKE_EXTRA_COMPILERS += protoc
SOURCES += \
QData.cpp \
QValue.cpp \
data.cpp \
main.cpp
HEADERS += \
QCbor_impl.h \
QData.h \
QJson_impl.h \
QSettings_impl.h \
QValue.h \
QVariant_impl.h \
QModel_impl.h \
QData_impl.h \
QXml_impl.h \
data.h
DISTFILES += \
DESIGN.md \
README.md \
persons.proto \
sample.ini \
samples.txt
#-------------------------------------------------
#
# Project created by QtCreator 2018-06-12T22:10:15
#
#-------------------------------------------------
QT += widgets
TARGET = QBind
CONFIG += c++11 console
CONFIG -= app_bundle
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# C++17 allows replacing 'if /*constexpr*/' with 'if constexpr' with little performance improvement
#gcc:QMAKE_CXXFLAGS += -std=c++1z
#msvc:QMAKE_CXXFLAGS += /std=c++17
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
gcc:QMAKE_CXXFLAGS += -ftemplate-backtrace-limit=0
#PROTO_FILE = persons.proto
#protoc.output = $${OUT_PWD}/${QMAKE_FILE_IN_BASE}.pb.cc
#protoc.variable_out = GENERATED_SOURCES
#protoc.input = PROTO_FILE
#win32 {
# PROTO_PATH = /path/to/protobuf-3.7.1-msvc2019
# DEFINES += PROTOBUF_USE_DLLS
# protoc.commands = $${PROTO_PATH}/bin/protoc -I=$$relative_path($${PWD}, $${OUT_PWD}) --cpp_out=. ${QMAKE_FILE_NAME}
# INCLUDEPATH += $${PROTO_PATH}/include
# DEPENDPATH += $${PROTO_PATH}/include
# LIBS += -L$${PROTO_PATH}/lib -llibprotobuf
#}
#QMAKE_EXTRA_COMPILERS += protoc
SOURCES += \
QData.cpp \
QValue.cpp \
data.cpp \
main.cpp
HEADERS += \
QCbor_impl.h \
QData.h \
QJson_impl.h \
QSettings_impl.h \
QValue.h \
QVariant_impl.h \
QModel_impl.h \
QData_impl.h \
QXml_impl.h \
data.h
DISTFILES += \
DESIGN.md \
README.md \
persons.proto \
sample.ini \
samples.txt
......@@ -108,9 +108,9 @@ public:
QCborWriter(QByteArray* io) : io(io) { Q_ASSERT(io); }
// Shortcuts
/**/ QValue value ( ) { return QCur(this).value(); }
/**/ QSequence sequence(quint32* s=nullptr) { return QCur(this).value().sequence(s); }
template<typename T> QCur bind ( T&& t) { return QCur(this).value().bind(std::forward<T>(t)); }
/**/ QValue value ( ) { return QCur(this).value(); }
/**/ QSequence sequence(quint32* s=nullptr) { return QCur(this).value().sequence(s); }
template<typename T> QValueEnd bind ( T&& t) { return QCur(this).value().bind(std::forward<T>(t)); }
protected:
bool isValid() const noexcept { return io; }
......@@ -348,13 +348,12 @@ protected:
n=float(d); return true; }
bool tryBind ( quint64& t) { if (caching) { return caching->tryBind(t) && cacheOut(); }
quint64 i; bool neg;
if (!getInteger(i,neg)) { handleError(qBindExpectedInteger ); return false; }
if ( neg ) { handleError(qBindExpectedPositiveInteger); return false; }
t=i; return true; }
skipTag();
if (!isUnsignedInteger()) { handleError(qBindExpectedPositiveInteger); return false; }
t=toUnsignedInteger(); return true; }
bool tryBind ( qint64& t) { if (caching) { return caching->tryBind(t) && cacheOut(); }
quint64 i; bool neg;
if (!getInteger(i,neg)) { handleError(qBindExpectedInteger ); return false; }
if (!getInteger(i,neg)) { return false; }
if ( neg ) { if (-quint64(std::numeric_limits<qint64>::max())-1<i) { handleError(qBindExpectedSmallerNumber); return false; } t=-qint64(i); return true; }
else { if ( quint64(std::numeric_limits<qint64>::max()) <i) { handleError(qBindExpectedSmallerNumber); return false; } t= qint64(i); return true; }
}
......@@ -420,7 +419,7 @@ protected:
return leaveContainer(); }
bool isValid() const noexcept { return const_cast<QCborReader*>(this)->lastError()==QCborError::NoError; }
bool handleError(QIdentifierLiteral e, QString context = QString()) const { return errorHandler ? errorHandler(e, QString("at %1 ").arg(currentOffset()).append(context)) : false; }
bool handleError(QIdentifierLiteral e, QString context = QString()) const { return errorHandler && errorHandler(e, QString("at %1 ").arg(currentOffset()).append(context)); }
private:
void skipTag() { if (isTag()) next(); }
bool getNumber(double& d) { skipTag();
......@@ -473,7 +472,6 @@ struct QTransmogrifier<QCborValue> {
if (j.isString ()) return v.bind(j.toString ());
if (j.isByteArray()) return v.bind(j.toByteArray());
if (j.isNull ()) return v.null();
if (j.isUndefined()) return v.any ();
return QValueEnd();
}
else { Q_ASSERT_X(!v, Q_FUNC_INFO, "Unsupported v->mode()"); return v.any(); }
......@@ -484,19 +482,17 @@ struct QTransmogrifier<QCborValue> {
}
else if (v->mode()==Read) {
QValueEnd r;
auto suspended = v->setErrorHandler();
QCborArray a; if ((r = v.bind(a))) { j = a ; v->setErrorHandler(suspended); return r; }
QCborMap o; if ((r = v.bind(o))) { j = o ; v->setErrorHandler(suspended); return r; }
QString t; if ((r = v.bind(t))) { j = QCborValue( t ); v->setErrorHandler(suspended); return r; }
bool b; if ((r = v.bind(b))) { j = QCborValue( b ); v->setErrorHandler(suspended); return r; }
qint64 i; if ((r = v.bind(i))) { j = QCborValue( i ); v->setErrorHandler(suspended); return r; }
v.setIsVariant();
QCborArray a; if ((r = v.bind(a))) { j = a ; return r; }
QCborMap o; if ((r = v.bind(o))) { j = o ; return r; }
QString t; if ((r = v.bind(t))) { j = QCborValue( t ); return r; }
bool b; if ((r = v.bind(b))) { j = QCborValue( b ); return r; }
qint64 i; if ((r = v.bind(i))) { j = QCborValue( i ); return r; }
quint64 u; if ((r = v.bind(u))) { Q_ASSERT(quint64(std::numeric_limits<qint64>::max())<u); // or tryBind<qint64>() would have succeeded
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; }
/**/ if ((r = v.null( ))) { j = QCborValue( nullptr ); v->setErrorHandler(suspended); return r; }
v->setErrorHandler(suspended);
if ((r = v.any())) { j = QCborValue(QCborValue::Undefined); }
j = QCborValue(double(u)); return r; }
double d; if ((r = v.bind(d))) { j = QCborValue( d ); return r; }
QByteArray y; if ((r = v.bind(y))) { j = QCborValue( y ); return r; }
/**/ if ((r = v.null( ))) { j = QCborValue( nullptr ); return r; }
return r;
}
else { Q_ASSERT_X(!v, Q_FUNC_INFO, "Unsupported v->mode()"); return v.any(); }
......
......@@ -151,7 +151,6 @@ private:
class QJsonWriter : public QAbstractValueWriter
{
Q_DISABLE_COPY(QJsonWriter)
Q_ENABLE_MOVE_DEFAULT(QJsonWriter)
public:
QJsonWriter( QIODevice* io) : io(io) { Q_ASSERT(io || ba); }
QJsonWriter(QByteArray* ba) : ba(ba) { Q_ASSERT(io || ba); }
......@@ -258,7 +257,8 @@ 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 tryAny ( ) { if (caching) { return caching->tryAny() && cacheOut(); }
return next(",}]"); }
bool tryNull ( ) { if (caching) { return caching->tryNull() && cacheOut(); }
if (get('n', "[{\"ntf-0123456789.") &&
get('u') &&
......@@ -310,28 +310,27 @@ protected:
if ( neg && i<quint64(-std::numeric_limits<qint64>::max())-1) { t = -qint64(i); cachedNumber=None; return true; }
handleError(qBindExpectedSmallerNumber); return false; }
bool tryBind ( QVariant& dst) { if (caching) { return caching->tryBind(dst) && cacheOut(); }
auto suspended = setErrorHandler();
quint32 size=0; QIdentifier key; QVariant item;
if ( trySequence(&size)) { setErrorHandler(suspended); QVariantList l; while (tryItem( )) { l.append( tryBind(item) ? item : QVariant()); } dst = l; return tryOut(); }
if ( tryRecord (&size)) { setErrorHandler(suspended); QVariantMap l; while (tryItem(key)) { l.insert(key.latin1(), tryBind(item) ? item : QVariant()); } dst = l; return tryOut(); }
bool b; if (tryBind(b)) { setErrorHandler(suspended); dst = QVariant(b ); return true; }
quint64 u; if (tryBind(u)) { setErrorHandler(suspended); dst = QVariant(u ); return true; } // may fail after consuming integer part
qint64 l; if (tryBind(l)) { setErrorHandler(suspended); dst = QVariant(l ); return true; } // may fail after consuming integer part
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);
{
QSuspendedValueErrorHandler(this);
quint32 size=0; QIdentifier key; QVariant item;
if ( trySequence(&size)) { QVariantList l; while (tryItem( )) { l.append( tryBind(item) ? item : QVariant()); } dst = l; return tryOut(); }
if ( tryRecord (&size)) { QVariantMap l; while (tryItem(key)) { l.insert(key.latin1(), tryBind(item) ? item : QVariant()); } dst = l; return tryOut(); }
bool b; if (tryBind(b)) { dst = QVariant(b ); return true; }
quint64 u; if (tryBind(u)) { dst = QVariant(u ); return true; } // may fail after consuming integer part
qint64 l; if (tryBind(l)) { dst = QVariant(l ); return true; } // may fail after consuming integer part
double d; if (tryBind(d)) { dst = QVariant(d+/*integer part consumed by one of*/u+l); return true; }
QUtf8Data s; if (tryBind(s)) {
QByteArray b;
if (toByteArray(b, s)) {
toVariant(dst, b);
return true;
}
dst = QVariant(QString::fromUtf8(s.utf8()));
return true;
}
dst = QVariant(QString::fromUtf8(s.utf8()));
return true;
if (tryNull()) { dst = QVariant::fromValue(nullptr); return true; }
}
if (tryNull()) { setErrorHandler(suspended); dst = QVariant::fromValue(nullptr); return true; }
setErrorHandler(suspended);
if (tryAny() || handleError(qBindUnexpectedValue)) { dst = QVariant(); return true; }
return false;
return handleError(qBindUnexpectedValue) && tryAny();
}
bool tryOut ( ) { if (caching) { bool out = caching->tryOut(); if (out) { cacheLevel--; cacheOut(); } return out; }
......@@ -346,6 +345,7 @@ protected:
if (levels.last().cachedItems. contains(QIdentifier(u))) { // must be checked before we consume tryItem(s)
cachedValue = levels.last().cachedItems.take(QIdentifier(u));
cacheReader.reset(&cachedValue);
cacheReader.setErrorHandler(errorHandler);
Q_ASSERT(!cacheLevel);
caching = &cacheReader; // let outer QCur drive QJsonReader depending on bound T
return true;
......@@ -359,7 +359,10 @@ protected:
else { // read cachedValue using a dedicated QCur and QTransmogrifier<QValue> accepting value of any 'shape' (outer QTransmogrifier is specialized on outer T which is not usually generic enough)
cachedValue = QJsonValue();
cacheWriter.reset(&cachedValue);
if (!QCur(this).value().bind(QCur(&cacheWriter).value())) return false;
cacheWriter.setErrorHandler(errorHandler);
if (!QCur(this).value().bind(QCur(&cacheWriter).value())) {
return false;
}
levels.last().cachedItems.insert(s, cachedValue);
continue; // until !tryItem(s) or u==s
}
......@@ -535,8 +538,7 @@ struct QTransmogrifier<QJsonValue> {
if (j.isDouble ()) return v.bind(j.toDouble());
if (j.isString ()) return v.bind(j.toString());
if (j.isNull ()) return v.null();
if (j.isUndefined()) return v.any ();
return QValueEnd();
return v;
}
else { Q_ASSERT_X(false, Q_FUNC_INFO, "Unsupported v->mode()"); return v.any(); }
}
......@@ -546,18 +548,16 @@ struct QTransmogrifier<QJsonValue> {
}
else if (v->mode()==Read) {
QValueEnd r;
auto suspended = v->setErrorHandler();
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.any())) { j = QJsonValue(QJsonValue::Undefined); }
return r;
v.setIsVariant();
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; }
/**/ if ((r = v.null( ))) { j = QJsonValue( ); return r; }
return v;
}
else { Q_ASSERT_X(!v, Q_FUNC_INFO, "Unsupported v->mode()"); return v.any(); }
}
......
......@@ -405,7 +405,6 @@ template <class TItemReader=QJsonReader>
class QModelReader : public QModelBind
{
Q_DISABLE_COPY(QModelReader)
Q_ENABLE_MOVE_DEFAULT(QModelReader)
public:
QModelReader(QAbstractItemModel* m, bool rowFirst=true) : QModelBind(m, rowFirst), r(&io) { io.open(QIODevice::ReadOnly); }
......
......@@ -104,7 +104,6 @@ class QSettingsReader : public QAbstractValueReader
{
Q_DISABLE_COPY(QSettingsReader)
public:
Q_ENABLE_MOVE_DEFAULT(QSettingsReader)
QSettingsReader(QSettings* s) : settings(s) { Q_ASSERT(s); levels.push(Level(qBindExpectedItem)); }
QString currentPath() const {
......
......@@ -2,7 +2,7 @@
QIdentifierLiteral qBindUnexpectedValue ("UnexpectedValue" );
QIdentifierLiteral qBindUnexpectedEnd ("UnexpectedEnd" );
QIdentifierLiteral qBindBlocked ("Blocked" );
QIdentifierLiteral qBindStopped ("Stopped" );
QIdentifierLiteral qBindExpectedItem ("ExpectedItem" );
QIdentifierLiteral qBindExpectedNull ("ExpectedNull" );
......
This diff is collapsed.
......@@ -119,7 +119,6 @@ class QVariantVisitor : public QAbstractValueReader
{
Q_DISABLE_COPY(QVariantVisitor)
public:
Q_ENABLE_MOVE_DEFAULT(QVariantVisitor)
QVariantVisitor(const QVariant* v) : value(v) { Q_ASSERT(v); }
void reset(const QVariant* v) { value=v; Q_ASSERT(v); levels.resize(0); }
......
......@@ -92,7 +92,7 @@ struct Person
.bind( lastName)
.out()
.bind("height" ,height )
.bind("age" ,age ,-1) // reads null() as -1
.bind("age" ,age ,-1) // reads unexpected values as -1
.bind("phones" ,phones ) // recursive calls to QTransmogrifier will take care of that part
.bind("comments",comments)
.bind("children",children)
......@@ -297,7 +297,6 @@ struct QTransmogrifier<QColor> {
class TextWriter : public QAbstractValueWriter
{
Q_DISABLE_COPY(TextWriter)
Q_ENABLE_MOVE_DEFAULT(TextWriter)
public:
TextWriter(QByteArray* utf8) : utf8(utf8) { Q_ASSERT(utf8); }
......@@ -916,12 +915,11 @@ int main(int argc, char *argv[])
r.bind(jv);
}
STOP("Json>JsonValue",QJsonDocument(jv.toObject()).toJson(QJsonDocument::Compact)+" | "+errors.join(", "));
// TODO
// START {
// ba.resize(0);
// QJsonWriter(&ba).bind(jv);
// }
// STOP("JsonValue>Json",ba);
START {
ba.resize(0);
QJsonWriter(&ba).bind(jv);
}
STOP("JsonValue>Json",ba);
START {
roundtrip.seek(0); ba.resize(0);
QJsonReader r(&roundtrip);
......@@ -1149,8 +1147,10 @@ void doGuiExample() {
persons[1].phones.append(Phone{Phone::Office,"112"});
QStringList errors;
auto handler = [&errors](QIdentifierLiteral name, QString context){ errors.append(context.append(name.latin1())); return true; };
auto ignore = [](QIdentifierLiteral, QString){ return true; };
auto handler = [&errors](QIdentifierLiteral name, QString context){
errors.append(context.append(name.latin1()));
return true;
};
// Various possibilities to customize bind
......
......@@ -56,15 +56,16 @@ Bindable |
Bindable>Cbor |bf647479706502666e756d6265726b2b34342031323334353637ff
Bindable>Json |{"type":2,"number":"+44 1234567"}
Person-Json |================================================================================
Json>P |(Person) names:[ John Doe] height:1.75 age:-1 phones:[] comments: children:[] | at 0:1 IgnoredCharacter, at 0:15 IgnoredCharacter, at 0:23 IgnoredCharacter, at 0:40 IgnoredCharacter
Json>P |(Person) names:[ John Doe] height:1.75 age:-1 phones:[] comments: children:[] | at 0:1 IgnoredCharacter, at 0:15 IgnoredCharacter, at 0:23 IgnoredCharacter, at 0:40 IgnoredCharacter, at 0:58 IgnoredCharacter, ExpectedDecimal, at 0:102 IgnoredCharacter, at 0:102 commentsIgnoredItem, at 0:102 UnexpectedEnd, at 0:103 UnexpectedValue, at 0:104 Stopped
P>Json |{"names":["John","Doe"],"height":1.7500000000000002,"age":-1,"phones":[],"comments":"","children":[]}
Json>P |(Person) names:[ John Doe] height:1.75 age:-1 phones:[] comments: children:[] |
P>JsonValue |{"age":-1,"children":[],"comments":"","height":1.7500000000000004,"names":["John","Doe"],"phones":[]}
JsonValue>P |(Person) names:[ John Doe] height:1.75 age:-1 phones:[] comments: children:[] |
Json>JsonValue|{"age":-1,"children":[],"comments":"","height":1.7500000000000004,"names":["John","Doe"],"phones":[]} |
JsonValue>Json|{"age":-1,"children":[],"comments":"","height":1.7500000000000004,"names":["John","Doe"],"phones":[]}
Json>Cbor |bf656e616d65739f644a6f686e63446f65ff66686569676874fa3fe0000063616765206670686f6e65739fff68636f6d6d656e747360686368696c6472656e9fffff
Person-Cbor |================================================================================
Cbor>P |(Person) names:[ John Doe] height:1.75 age:-1 phones:[] comments: children:[] | at 41 commentsIgnoredItem, at 41 UnexpectedEnd, at 58 UnexpectedValue
Cbor>P |(Person) names:[ John Doe] height:1.75 age:-1 phones:[] comments: children:[] | at 41 commentsIgnoredItem, at 41 UnexpectedEnd, at 58 UnexpectedValue, at 58 Stopped
P>Cbor |bf656e616d65739f644a6f686e63446f65ff66686569676874fb3ffc00000000000063616765206670686f6e65738068636f6d6d656e747360686368696c6472656e80ff
Cbor>P |(Person) names:[ John Doe] height:1.75 age:-1 phones:[] comments: children:[] |
QCborStream>P |(Person) names:[ John Doe] height:1.75 age:-1 phones:[] comments: children:[] | true
......@@ -72,7 +73,7 @@ P>CborValue |a6656e616d657382644a6f686e63446f6566686569676874fb3ffc00000000000
CborValue>P |(Person) names:[ John Doe] height:1.75 age:-1 phones:[] comments: children:[] |
Cbor>CborValue|{"names": ["John", "Doe"], "height": 1.75, "age": -1, "phones": [], "comments": "", "children": []} |
CborValue>Cbor|a6656e616d657382644a6f686e63446f6566686569676874fb3ffc00000000000063616765206670686f6e65738068636f6d6d656e747360686368696c6472656e80
Cbor>Json |{"names":["John","Doe"],"height":1.75,"age":undefined} |
Cbor>Json |{"names":["John","Doe"],"height":1.75,"age":-1,"phones":[],"comments":"","children":[]} |
Person-Settings|================================================================================
P>Settings |(Person) names:[ John Doe] height:1.75 age:18 phones:[] comments:unicode is likely U+01  + U+1F  + U+A4 ¤ U+B0 ° U+D8 Ø U+FF ÿ children:[]
Settings>P |(Person) names:[ John Doe] height:1.75 age:18 phones:[] comments:unicode is likely U+01  + U+1F  + U+A4 ¤ U+B0 ° U+D8 Ø U+FF ÿ children:[] | at /-1/ namesIgnoredItem, at /-1/ UnexpectedEnd, at /-1 UnexpectedValue
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment