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

WIP Optional reportError capability from anywhere with automatic

detection of expected shape
Introduced min cardinality in fluent interface envisioning the addition
of item(2,3).any() syntax...
parent a268a829
......@@ -64,7 +64,14 @@ protected: \
enum BindMode { Read, Write }; //!< drives QBind<TResult,T>() traversal and processing (the design would support others like Append)
struct QTextReadError { QByteArray error; int line; int column; int index; };
static const char* qBindExpectedNull = "Expected null" ;
static const char* qBindExpectedSequence = "Expected sequence";
static const char* qBindExpectedRecord = "Expected record" ;
static const char* qBindExpectedItem = "Expected item" ;
static const char* qBindExpectedText = "Expected text" ;
static const char* qBindExpectedDecimal = "Expected decimal" ;
static const char* qBindExpectedBoolean = "Expected boolean" ;
static const char* qBindIgnoredCharacter = "Ignored character";
template<class T_> class Rec; //!< a Record data structure (not defined in this Proof-Of-Concept for the sake of simplicity)
template<class T_> class Seq; //!< a Sequence data structure defined below
......@@ -81,11 +88,11 @@ public:
operator bool() { return m_out.operator bool(); } //!< to drive QBind<TResult,T>() traversal
TImpl* operator->() { return m_out.operator ->(); }
/**/ Seq<T_> sequence() { if (Q_LIKELY(m_out) && m_out->_sequence()) return Seq<T_>(std::move(m_out)); return Seq<T_>(); }
/**/ T_ null() { if (Q_LIKELY(m_out) && m_out-> _null()) return std::move(m_out) ; return T_ (); }
template<typename T> T_ bind(const T& t) { if (Q_LIKELY(m_out) && m_out-> _bind(t)) return std::move(m_out) ; return T_ (); }
template<typename T> T_ bind( T& t) { if (Q_LIKELY(m_out) && m_out-> _bind(t)) return std::move(m_out) ; return T_ (); }
template<typename T> T_ bind( T&& t) { if (Q_LIKELY(m_out) && m_out-> _bind(t)) return std::move(m_out) ; return T_ (); }
/**/ Seq<T_> sequence(int min=1) { if (Q_LIKELY(m_out) && m_out-> _sequence(min)) return Seq<T_>(std::move(m_out)); return Seq<T_>(); }
/**/ T_ null(int min=1) { if (Q_LIKELY(m_out) && m_out-> _null(min)) return std::move(m_out) ; return T_ (); }
template<typename T> T_ bind(const T& t,int min=1) { if (Q_LIKELY(m_out) && m_out-> _bind(t,min)) return std::move(m_out) ; return T_ (); }
template<typename T> T_ bind( T& t,int min=1) { if (Q_LIKELY(m_out) && m_out-> _bind(t,min)) return std::move(m_out) ; return T_ (); }
template<typename T> T_ bind( T&& t,int min=1) { if (Q_LIKELY(m_out) && m_out-> _bind(t,min)) return std::move(m_out) ; return T_ (); }
private:
// Val<TResult> innerValue() { return Val<TResult>(/*TResult*/(m_out)); }
// may not compile without a Seq member returning a TResult without side-effect (TItem is not available as in modmed)
......@@ -107,25 +114,27 @@ public:
operator bool() { return m_out.operator bool(); } //!< to drive QBind<TResult,T>() traversal
TImpl* operator->() { return m_out.operator ->(); }
Val<Seq<T_>> item() { if (Q_LIKELY(m_out) && m_out->_item()) return Val<Seq<T_>>(std::move(*this)); return Val<Seq<T_>>(); }
/**/ T_ out() { if (Q_LIKELY(m_out) && m_out-> _out()) return std::move(m_out) ; return T_ (); }
Val<Seq<T_>> item(int min=1) { if (Q_LIKELY(m_out) && m_out->_item(min)) return Val<Seq<T_>>(std::move(*this)); return Val<Seq<T_>>(); }
/**/ T_ out(int min=1) { if (Q_LIKELY(m_out) && m_out-> _out(min)) return std::move(m_out) ; return T_ (); }
operator TResult() { return out(); /* recursively calls operator TResult() as mandated by T_ */ }
TResult result() { return operator TResult(); }
// Shortcuts
template<typename T> Seq<T_> bind(const T& t) { if (itemValue().bind(t)) return std::move(*this); return Seq<T_>(); } // binding Val<T_> instead of Val<Seq<T_>> requires less code generation
template<typename T> Seq<T_> bind( T& t) { if (itemValue().bind(t)) return std::move(*this); return Seq<T_>(); }
template<typename T> Seq<T_> bind( T&& t) { if (itemValue().bind(t)) return std::move(*this); return Seq<T_>(); }
template<typename T> Seq<T_> bind(const T& t,int min=1) { if (itemValue(min).bind(t,min)) return std::move(*this); return Seq<T_>(); } // binding Val<T_> instead of Val<Seq<T_>> requires less code generation
template<typename T> Seq<T_> bind( T& t,int min=1) { if (itemValue(min).bind(t,min)) return std::move(*this); return Seq<T_>(); }
template<typename T> Seq<T_> bind( T&& t,int min=1) { if (itemValue(min).bind(t,min)) return std::move(*this); return Seq<T_>(); }
private:
template<class TResult, typename T> friend class QBind;
Val<T_> itemValue() { if (Q_LIKELY(m_out) && m_out->_item()) { T_ scopedT(m_out); return std::move(Val<T_>(std::move(scopedT))); } return Val<T_>(); } // the m_out copy must be scoped and will be invalid when the original is destroyed
Val<T_> itemValue(int min=1) { if (Q_LIKELY(m_out) && m_out->_item(min)) { T_ scopedT(m_out); return std::move(Val<T_>(std::move(scopedT))); } return Val<T_>(); } // the m_out copy must be scoped and will be invalid when the original is destroyed
T_ m_out = T_();
};
//! Base class for TResult classes that require a single heap allocation (and lock)
//! but are simple to implement and de facto pimpled
//! Base class for TResult classes that require a single heap allocation (and lock), but:
//! - are simple to implement
//! - hide implementation methods from the fluent interface
//! - are de facto pimpled
template<class TResult_, class TImpl_, BindMode Mode_>
class QScopedResult
{
......@@ -143,26 +152,28 @@ public:
operator bool() { return m; } //!< to drive QBind<TResult,T>() traversal
TImpl* operator->() { Q_ASSERT_X(m,Q_FUNC_INFO,"check operator bool() before calling operator->()"); return m; }
void reportError(const char*) { /* a TResult with BindMode::Write will only encounter write errors */ }
Val<TResult> value() { return Val<TResult>(std::move(*static_cast<TResult*>(this))); }
// Shortcuts
/**/ Seq<TResult> sequence() { /* return value().sequence(); */ if (Q_LIKELY(m) && m->_sequence()) return Seq<TResult>(std::move(*static_cast<TResult*>(this))); return Seq<TResult>(); }
/**/ TResult null() { /* return value(). null(); */ if (Q_LIKELY(m) && m-> _null()) return std::move(*static_cast<TResult*>(this)) ; return TResult (); }
template<typename T> TResult bind(const T& t) { /* return value(). bind(t); */ if (Q_LIKELY(m) && m-> _bind(t)) return std::move(*static_cast<TResult*>(this)) ; return TResult (); }
template<typename T> TResult bind( T& t) { /* return value(). bind(t); */ if (Q_LIKELY(m) && m-> _bind(t)) return std::move(*static_cast<TResult*>(this)) ; return TResult (); }
template<typename T> TResult bind( T&& t) { /* return value(). bind(t); */ if (Q_LIKELY(m) && m-> _bind(t)) return std::move(*static_cast<TResult*>(this)) ; return TResult (); }
/**/ Seq<TResult> sequence(int min=1) { /* return value().sequence(); */ if (Q_LIKELY(m) && m->_sequence(min)) return Seq<TResult>(std::move(*static_cast<TResult*>(this))); return Seq<TResult>(); }
/**/ TResult null(int min=1) { /* return value(). null(); */ if (Q_LIKELY(m) && m-> _null(min)) return std::move(*static_cast<TResult*>(this)) ; return TResult (); }
template<typename T> TResult bind(const T& t,int min=1) { /* return value(). bind(t); */ if (Q_LIKELY(m) && m-> _bind(t,min)) return std::move(*static_cast<TResult*>(this)) ; return TResult (); }
template<typename T> TResult bind( T& t,int min=1) { /* return value(). bind(t); */ if (Q_LIKELY(m) && m-> _bind(t,min)) return std::move(*static_cast<TResult*>(this)) ; return TResult (); }
template<typename T> TResult bind( T&& t,int min=1) { /* return value(). bind(t); */ if (Q_LIKELY(m) && m-> _bind(t,min)) return std::move(*static_cast<TResult*>(this)) ; return TResult (); }
protected:
QScopedResult(TImpl* result, bool owned) : m(result), m_owned(owned) {}
TImpl* m = nullptr;
bool m_owned = true ; //!< for nested QBind only
TImpl* m = nullptr;
bool m_owned = true ; //!< for nested QBind only
};
//! Base class for TResult classes that can exhibit high performance (they require no heap allocation and no lock)
//! \warning
//! - it is more difficult to correctly implement a TResult derived from QMovedResult, especially with internal state (need to understand move semantics)
//! - TResult scoped copies do not share state (such as the whole path to the current value)
//! - TResult is not pimpled by default
//! - TResult is not automatically pimpled
template<class TResult_, BindMode Mode_>
class QMovedResult
{
......@@ -179,11 +190,26 @@ public:
Val<TResult> value() { return Val<TResult>(std::move(*static_cast<TResult*>(this))); }
// Shortcuts
/**/ Seq<TResult> sequence() { /* return value().sequence(); */ TResult* r=static_cast<TResult*>(this); if (Q_LIKELY(*r) && r->_sequence()) return Seq<TResult>(std::move(*r)); return Seq<TResult>(); }
/**/ TResult null() { /* return value(). null(); */ TResult* r=static_cast<TResult*>(this); if (Q_LIKELY(*r) && r-> _null()) return std::move(*r) ; return TResult (); }
template<typename T> TResult bind(const T& t) { /* return value(). bind(t); */ TResult* r=static_cast<TResult*>(this); if (Q_LIKELY(*r) && r-> _bind(t)) return std::move(*r) ; return TResult (); }
template<typename T> TResult bind( T& t) { /* return value(). bind(t); */ TResult* r=static_cast<TResult*>(this); if (Q_LIKELY(*r) && r-> _bind(t)) return std::move(*r) ; return TResult (); }
template<typename T> TResult bind( T&& t) { /* return value(). bind(t); */ TResult* r=static_cast<TResult*>(this); if (Q_LIKELY(*r) && r-> _bind(t)) return std::move(*r) ; return TResult (); }
/**/ Seq<TResult> sequence(int min=1) { /* return value().sequence(min); */ TResult* r=static_cast<TResult*>(this); if (Q_LIKELY(*r) && r->_sequence(min)) return Seq<TResult>(std::move(*r)); return Seq<TResult>(); }
/**/ TResult null(int min=1) { /* return value(). null(min); */ TResult* r=static_cast<TResult*>(this); if (Q_LIKELY(*r) && r-> _null(min)) return std::move(*r) ; return TResult (); }
template<typename T> TResult bind(const T& t,int min=1) { /* return value(). bind(t,min); */ TResult* r=static_cast<TResult*>(this); if (Q_LIKELY(*r) && r-> _bind(t,min)) return std::move(*r) ; return TResult (); }
template<typename T> TResult bind( T& t,int min=1) { /* return value(). bind(t,min); */ TResult* r=static_cast<TResult*>(this); if (Q_LIKELY(*r) && r-> _bind(t,min)) return std::move(*r) ; return TResult (); }
template<typename T> TResult bind( T&& t,int min=1) { /* return value(). bind(t,min); */ TResult* r=static_cast<TResult*>(this); if (Q_LIKELY(*r) && r-> _bind(t,min)) return std::move(*r) ; return TResult (); }
};
#include <QtCore/qbuffer.h>
template<class TWriter>
class Utf8Result
{
public:
template<typename T> Utf8Result(const T& t) : m_writer(&m_result) { m_result.open(QIODevice::WriteOnly); m_writer.bind(t); }
template<typename T> Utf8Result( T&& t) : m_writer(&m_result) { m_result.open(QIODevice::WriteOnly); m_writer.bind(t); }
operator QByteArray() const { return m_result.buffer(); }
private:
QBuffer m_result;
TWriter m_writer;
};
// //////////////////////////////////////////////////////////////////////////
......@@ -216,6 +242,29 @@ struct QBind<TResult, std::nullptr_t> { static TResult bind(Val<TResult> value,
return value.null();
}};
template<class TResult>
struct QBind<TResult, const bool> { static TResult bind(Val<TResult> dst, const bool& src) {
static_assert(TResult::Mode==Write,"Cannot Read from TResult into const bool&");
return dst.bind(src ? "true" : "false");
}};
template<class TResult>
struct QBind<TResult, bool> {
static TResult bind(Val<TResult> dst, bool& src, std::enable_if_t<TResult::Mode==Write>* = nullptr) {
return dst.bind(src ? "true" : "false");
}
// C++17 constexpr if is required to handle situations where one of these definitions is not used
static TResult bind(Val<TResult> src, bool& dst, std::enable_if_t<TResult::Mode==Read >* = nullptr) {
QByteArray ba;
TResult r = src.bind(ba);
if (r) {
if (ba.toLower()=="true" ) dst = true ;
else if (ba.toLower()=="false") dst = false;
else r.reportError(qBindExpectedBoolean);
}
return r;
}
};
template<class TResult>
struct QBind<TResult, const int> { static TResult bind(Val<TResult> dst, const int& src) {
static_assert(TResult::Mode==Write,"Cannot Read from TResult into const int&");
......@@ -266,6 +315,20 @@ struct QBind<TResult, float> {
}
};
#include <QtCore/qbytearray.h>
template<class TResult>
struct QBind<TResult, const QByteArray> { static TResult bind(Val<TResult> dst, const QByteArray& src) {
static_assert(TResult::Mode==Write,"Cannot Read from TResult into const QByteArray&");
return dst.bind(src.constData());
}};
template<class TResult>
struct QBind<TResult, QByteArray> {
static TResult bind(Val<TResult> dst, QByteArray& src, std::enable_if_t<TResult::Mode==Write>* = nullptr) {
return dst.bind(src.constData());
}
};
#include <QtCore/qstring.h>
template<class TResult>
......@@ -312,7 +375,7 @@ struct QBind<TResult, QVector<T>> {
// C++17 constexpr if is required to handle situations where one of these definitions is not used
static TResult bind(Val<TResult> src, QVector<T>& dst, std::enable_if_t<TResult::Mode==Read >* = nullptr) {
auto s(src.sequence());
for (auto i = s.item(); i; i = s.item()) {
for (auto i = s.item(0); i; i = s.item(0)) {
T t;
s = i.bind(t);
if (s)
......@@ -331,11 +394,11 @@ struct QBind<TSrcResult, Val<TDst>> { static TSrcResult bind(Val<TSrcResult> src
static_assert(TDst ::Mode==Write,"cannot write to TDst" );
Seq<TSrcResult> srcSeq; Seq<TDst> dstSeq;
if ( srcSeq = src.sequence()) {
if ( srcSeq = src.sequence(0)) {
/**/ dstSeq = dst.sequence();
Val<TSrcResult> srcVal; Val<TDst> dstVal;
while (srcVal = srcSeq.itemValue()) { // using item()'s Val<Seq<TSrcResult> would cause an infinite compiler loop to generate corresponding QBind<Val<Seq<Seq<...>>,_> functions
while (srcVal = srcSeq.itemValue(0)) { // using item()'s Val<Seq<TSrcResult> would cause an infinite compiler loop to generate corresponding QBind<Val<Seq<Seq<...>>,_> functions
dstVal = dstSeq.itemValue();
srcSeq = QBind<TSrcResult, Val<TDst>>::bind(std::move(srcVal), dstVal);
}
......@@ -346,10 +409,10 @@ struct QBind<TSrcResult, Val<TDst>> { static TSrcResult bind(Val<TSrcResult> src
TSrcResult srcRes;
double d; if (srcRes = src.bind(d)) { dst.bind(d); return srcRes; }
double d; if (srcRes = src.bind(d,0)) { dst.bind(d); return srcRes; }
// TODO other native types we do not want to treat as text: bool, qlonglong, qulonglong, float (to optimize CborWriter output)
QString t; if (srcRes = src.bind(t)) { dst.bind(t); return srcRes; }
QString t; if (srcRes = src.bind(t,0)) { dst.bind(t); return srcRes; }
/**/ dst.null();
return src.null();
......
......@@ -121,52 +121,38 @@ protected:
friend class QMovedResult<CborWriter, BindMode::Write>;
template<class T_> friend class Val; // calls methods below
bool _sequence() { levels++;
io->putChar(cbor::IndefiniteLengthArrayByte);
return true; }
bool _null() { io->putChar(cbor::NullByte);
return true; }
bool _bind(const char* s) { putInteger (cbor::TextStringType, strlen(s));
io->write(s);
return true; }
bool _sequence(int min=1) { levels++; return io->putChar(cbor::IndefiniteLengthArrayByte) || min<=0; }
bool _null(int min=1) { return io->putChar(cbor:: NullByte) || min<=0; }
bool _bind(const char* s,int min=1) { return (putInteger(cbor::TextStringType, strlen(s)) && io->write(s)) || min<=0; }
// Natively supported overloads
bool _bind( float n) { io->putChar((cbor::SimpleTypesType << cbor::MajorTypeShift) | cbor::SinglePrecisionFloat);
union { float value; quint32 bits; } number;
number.value = n;
char bytes[sizeof(number.bits)];
qToBigEndian(number.bits, bytes);
io->write(bytes, sizeof(bytes));
return true; }
bool _bind( double n) { io->putChar((cbor::SimpleTypesType << cbor::MajorTypeShift) | cbor::DoublePrecisionFloat);
union { double value; quint64 bits; } number;
number.value = n;
char bytes[sizeof(number.bits)];
qToBigEndian(number.bits, bytes);
io->write(bytes, sizeof(bytes));
return true; }
bool _bind( float n,int min=1) { union { float value; quint32 bits; } number = { n };
char bytes[sizeof(number.bits)]; qToBigEndian(number.bits, bytes);
return (io->putChar((cbor::SimpleTypesType << cbor::MajorTypeShift) | cbor::SinglePrecisionFloat) && io->write(bytes, sizeof(bytes))) || min<=0; }
bool _bind( double n,int min=1) { union { double value; quint64 bits; } number = { n };
char bytes[sizeof(number.bits)]; qToBigEndian(number.bits, bytes);
return (io->putChar((cbor::SimpleTypesType << cbor::MajorTypeShift) | cbor::DoublePrecisionFloat) && io->write(bytes, sizeof(bytes))) || min<=0; }
// Val<TResult> prevents QBind from getting out() of an outer Seq for instance
template<typename T> bool _bind(const T& t) { return QBind<TResult,T>::bind(TResult(*this).value(), const_cast<T&>(t)); } // t will not be modified anyway
template<typename T> bool _bind( T& t) { return QBind<TResult,T>::bind(TResult(*this).value(), t ); }
template<typename T> bool _bind( T&& t) { return QBind<TResult,T>::bind(TResult(*this).value(), t ); }
template<typename T> bool _bind(const T& t,int min=1) { return QBind<TResult,T>::bind(TResult(*this).value(), const_cast<T&>(t)) || min<=0; } // t will not be modified anyway
template<typename T> bool _bind( T& t,int min=1) { return QBind<TResult,T>::bind(TResult(*this).value(), t ) || min<=0; }
template<typename T> bool _bind( T&& t,int min=1) { return QBind<TResult,T>::bind(TResult(*this).value(), t ) || min<=0; }
template<class T_> friend class Seq; // calls methods below
bool _item() { return true; }
bool _out() { io->putChar(cbor::BreakByte); levels--; return true; }
bool _item(int min=1) { Q_UNUSED(min); return true ; }
bool _out(int max=-1) { Q_UNUSED(max); levels--; return io->putChar(cbor::BreakByte); }
private:
void putInteger(char majorType, quint64 n)
bool putInteger(char majorType, quint64 n)
{
// See https://tools.ietf.org/html/rfc7049#section-2.2 if more performance is needed
if (n < 24) {
io->putChar((majorType << cbor::MajorTypeShift) | n);
if (n < 24) { return io->putChar((majorType << cbor::MajorTypeShift) | n);
} else {
char bytes[8];
if (n <= 0xff ) { io->putChar((majorType << cbor::MajorTypeShift) | cbor::Value8Bit ); qToBigEndian(quint8 (n),bytes); io->write(bytes,sizeof(quint8 )); }
else if (n <= 0xffff ) { io->putChar((majorType << cbor::MajorTypeShift) | cbor::Value16Bit); qToBigEndian(quint16(n),bytes); io->write(bytes,sizeof(quint16)); }
else if (n <= 0xffffffffL) { io->putChar((majorType << cbor::MajorTypeShift) | cbor::Value32Bit); qToBigEndian(quint32(n),bytes); io->write(bytes,sizeof(quint32)); }
else { io->putChar((majorType << cbor::MajorTypeShift) | cbor::Value64Bit); qToBigEndian( n ,bytes); io->write(bytes,sizeof(quint64)); }
if (n <= 0xff ) { qToBigEndian(quint8 (n),bytes); return io->putChar((majorType << cbor::MajorTypeShift) | cbor::Value8Bit ) && io->write(bytes,sizeof(quint8 )); }
if (n <= 0xffff ) { qToBigEndian(quint16(n),bytes); return io->putChar((majorType << cbor::MajorTypeShift) | cbor::Value16Bit) && io->write(bytes,sizeof(quint16)); }
if (n <= 0xffffffffL) { qToBigEndian(quint32(n),bytes); return io->putChar((majorType << cbor::MajorTypeShift) | cbor::Value32Bit) && io->write(bytes,sizeof(quint32)); }
else { qToBigEndian( n ,bytes); return io->putChar((majorType << cbor::MajorTypeShift) | cbor::Value64Bit) && io->write(bytes,sizeof(quint64)); }
}
}
......
This diff is collapsed.
......@@ -73,6 +73,7 @@ struct Person
#include <type_traits>
#include <QtCore/qiodevice.h>
#include <QtCore/qbuffer.h>
class TextWriter : public QMovedResult<TextWriter, BindMode::Write>
{
......@@ -82,26 +83,29 @@ public:
TextWriter(QIODevice* io) : io(io) { Q_ASSERT(io); }
operator bool() { return io; } // for QMovedResult
void reportError(const char*) { /* a TResult with BindMode::Write will only encounter write errors */ }
protected:
friend class QMovedResult<TextWriter, BindMode::Write>;
template<class T_> friend class Val; // enables calling methods below through operator->()
bool _null() { return true; }
bool _sequence() { io->write("["); return true; }
bool _bind(const char* s) { io->write( s ); return true; }
bool _null(int min=1) { return true || min<=0; }
bool _sequence(int min=1) { return io->write("[") || min<=0; }
bool _bind(const char* s, int min=1) { return io->write( s ) || min<=0; }
// Val<TResult> prevents QBind from getting out() of an outer Seq for instance
template<typename T> bool _bind(const T& t) { return QBind<TResult,T>::bind(TResult(*this).value(), const_cast<T&>(t)); } // t will not be modified anyway
template<typename T> bool _bind( T& t) { return QBind<TResult,T>::bind(TResult(*this).value(), t ); }
template<typename T> bool _bind( T&& t) { return QBind<TResult,T>::bind(TResult(*this).value(), t ); }
template<typename T> bool _bind(const T& t,int min=1) { return QBind<TResult,T>::bind(TResult(*this).value(), const_cast<T&>(t)) || min<=0; } // t will not be modified anyway
template<typename T> bool _bind( T& t,int min=1) { return QBind<TResult,T>::bind(TResult(*this).value(), t ) || min<=0; }
template<typename T> bool _bind( T&& t,int min=1) { return QBind<TResult,T>::bind(TResult(*this).value(), t ) || min<=0; }
template<class T_> friend class Seq; // enables calling methods below through operator->()
bool _item() { io->write(" "); return true; }
bool _out() { io->write("]"); return true; }
bool _item(int min=1) { return io->write(" ") || min<=0; }
bool _out(int max=-1) { Q_UNUSED(max); return io->write("]") ; }
private:
QIODevice* io = nullptr; // for QMovedResult
};
using Text = Utf8Result<TextWriter>;
// //////////////////////////////////////////////////////////////////////////
// Tests and Benchmarks
......@@ -301,31 +305,32 @@ int main()
json.buffer() = "_[ _\"John\" _, \"Doe\" , _1.75 , [ \"+44 1234567\" , \"+44 2345678\" ], \"superfluous item\" _] ";
QJsonValue v;
Person p;
QVector<QTextReadError> errors;
QVector<QJsonReaderImpl::Error> jsonReaderErrors ;
QVector< JsonVisitor::Error> jsonVisitorErrors;
START {
json.seek(0); b.seek(0); b.buffer().clear();
QJsonReader(&json).bind(QCborWriter(&b).value());
jsonReaderErrors = QJsonReader(&json).bind(CborWriter(&b).value())->errors;
}
STOP("Json>Cbor",QString::fromUtf8(b.buffer().toHex()))
START {
json.seek(0); v = QJsonValue();
errors = QJsonReader(&json).bind(v)->errors;
jsonReaderErrors = QJsonReader(&json).bind(v)->errors;
}
STOP("Json>JsonValue",QString::fromUtf8(QJsonDocument(v.toArray()).toJson())+QString(" errors:%1").arg(errors.size()));
STOP("Json>JsonValue",QString::fromUtf8(QJsonDocument(v.toArray()).toJson()+Text(jsonReaderErrors)));
START {
json.seek(0); p = {};
errors = QJsonReader(&json).bind(p)->errors;
jsonReaderErrors = QJsonReader(&json).bind(p)->errors;
}
STOP("Json>T",QString("[%1,%2,%3,[..%4..]] errors:%5").arg(p.firstName,p.lastName).arg(p.height).arg(p.phones.size()).arg(errors.size()))
STOP("Json>T",QString::fromUtf8(Text(p)+Text(jsonReaderErrors)))
START {
QJsonBuilder(&v).bind(p);
}
STOP("T>JsonValue",QString::fromUtf8(QJsonDocument(v.toArray()).toJson()));
START {
p = {};
JsonVisitor(&v).bind(p);
jsonVisitorErrors = JsonVisitor(&v).bind(p)->errors;
}
STOP("JsonValue>T",QString("[%1,%2,%3,[..%4..]] errors:%5").arg(p.firstName,p.lastName).arg(p.height).arg(p.phones.size()).arg(errors.size()))
STOP("JsonValue>T",QString::fromUtf8(Text(p)+Text(jsonVisitorErrors)))
START {
b.seek(0); b.buffer().clear();
CborWriter(&b).bind(p);
......
Supports Markdown
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