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

Added support for .any() "wildcard" to allow partial QBind and data

schema evolution
parent 1cd6dcfe
......@@ -124,6 +124,8 @@ struct BindNative {};
struct BindGeneric {};
template<class TImpl, typename T, typename TEnabledIf=void> struct BindSupport : BindGeneric {};
template<class TImpl> struct BindSupport<TImpl,void,void> : BindGeneric {};
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
......@@ -140,12 +142,15 @@ public:
operator bool() { return m_out.operator bool(); } //!< to drive QBind<TResult,T>() traversal
TImpl* operator->() { return m_out.operator ->(); }
template<typename T> T_ bind(T&& t) { if (_bind(std::forward<T>(t),BindSupport<TImpl,T>())) return std::move(m_out) ; else return T_ (); }
/**/ T_ null () { if (Q_LIKELY(m_out) && m_out-> _null()) return std::move(m_out) ; else return T_ (); }
/**/ Seq<T_> sequence () { if (Q_LIKELY(m_out) && m_out-> _sequence()) return Seq<T_>(std::move(m_out)); else return Seq<T_>(); }
/**/ T_ null () { if (Q_LIKELY(m_out) && m_out-> _null()) return std::move(m_out) ; else return T_ (); }
/**/ Seq<T_> sequence () { if (Q_LIKELY(m_out) && m_out-> _sequence()) return Seq<T_>(std::move(m_out)); else return Seq<T_>(); }
template<typename T> T_ bind(T&& t) { if (_bind(BindSupport<TImpl, T>(),std::forward<T>(t))) return std::move(m_out) ; else return T_ (); }
/**/ T_ any () { if (_bind(BindSupport<TImpl,void>() )) return std::move(m_out) ; else return T_ (); }
private:
template<typename T> bool _bind(T&& t, BindNative ) { return Q_LIKELY(m_out) && m_out->_bind( std::forward<T>(t)); }
template<typename T> bool _bind(T&& t, BindGeneric) { return QBind<TResult,T&&>::bind(Val<TResult>(m_out._unsafeCopy()),std::forward<T>(t)); }
template<typename T> bool _bind(BindNative , T&& t) { return Q_LIKELY(m_out) && m_out->_bind( std::forward<T>(t)); }
template<typename T> bool _bind(BindGeneric, T&& t) { return QBind<TResult, T&&>::bind(Val<TResult>(m_out._unsafeCopy()),std::forward<T>(t)); }
/**/ bool _bind(BindNative ) { return Q_LIKELY(m_out) && m_out->_bind( ); }
/**/ bool _bind(BindGeneric ) { return QBind<TResult,void>::bind(Val<TResult>(m_out._unsafeCopy()) ); }
T_ m_out = T_(); //!< moved context of current traversal up to TResult that will reference the val itself (be it a QIODevice or QCborValue)
};
......@@ -171,7 +176,10 @@ public:
TResult result() { return operator TResult(); }
// Shortcuts
template<typename T> Seq<T_> bind(T&& t) { return item().bind(std::forward<T>(t)); }
/**/ Seq<T_> any () { return item().any (); }
/**/ Seq<T_> null () { return item().null (); }
/**/ Seq<Seq<T_>> sequence () { return item().sequence (); }
template<typename T> Seq<T_> bind(T&& t) { return item().bind(std::forward<T>(t)); }
private:
template<class TSrcResult, typename TDst, typename TEnabledIf> friend struct QBind; // restricting to <TSrcResult, Val<TDst>&&, IsReader<TSrcResult>>; is not possible in C++11
Val<TResult> _unsafeItem(int min= 1) { if (Q_LIKELY(m_out) && m_out->_item(min)) return Val<TResult>(m_out._unsafeCopy()); else return Val<TResult>(); }
......@@ -277,6 +285,26 @@ private:
// //////////////////////////////////////////////////////////////////////////
// QBind partial specializations (generic on TResult, usually not on TResult::Mode for dynamically-sized or builtin types)
template<class TResult>
struct QBind<TResult, void, IsWriter<TResult>> { static TResult bind(Val<TResult> dst) {
return dst.null();
}};
template<class TResult>
struct QBind<TResult, void, IsReader<TResult>> { static TResult bind(Val<TResult> src) {
TResult srcRes;
{
ScopedChoice<Val<TResult>> choice(src);
Seq<TResult> srcSeq;
if (srcSeq = src.sequence()) {
return srcSeq.out();
}
QString t; if (srcRes = src.bind(t)) { return srcRes; }
}
return src.null();
}};
#include <cstddef>
template<class TResult>
......
......@@ -115,8 +115,8 @@ protected:
friend class QMovedWriter<CborWriter>;
template<class T_> friend class Val; // calls methods below
bool _sequence() { levels++; return io->putChar(cbor::IndefiniteLengthArrayByte) ; }
bool _null() { return io->putChar(cbor:: NullByte) ; }
bool _sequence() { levels++; return io->putChar(cbor::IndefiniteLengthArrayByte) ; }
bool _bind(const char* s) { return (putInteger(cbor::TextStringType, strlen(s)) && io->write(s)); }
// Natively supported overloads
......
......@@ -375,12 +375,13 @@ protected:
double d; qlonglong i; bool isNegative;
auto r=getNumber(d, i, isNegative); if (r) t=(isNegative?-i:i); return r; }
bool _any() { QByteArray t; double d; bool b;
bool _bind() { QByteArray t; double d; bool b;
return (_sequence() && _out())
|| _bind(t)
|| _bind(d)
|| _null()
|| _bind(b)
|| _null(); }
|| _bind(d)
|| _bind(t) // including any other?
;}
template<class T_> friend class Seq; // calls methods below
......@@ -394,7 +395,7 @@ protected:
return true; }
bool _out(int max=-1) { auto level = levels.pop();
while ((max<0 || 0<max--) && get(',', level.end)) {
_any();
_bind();
}
return get(*level.end, "}"); }
......@@ -503,6 +504,7 @@ private:
}
};
QJsonReader::QJsonReader(QIODevice* io) : QScopedResult(new QJsonReaderImpl(io), true) {}
template<> struct BindSupport<QJsonReaderImpl, void> : BindNative {};
template<> struct BindSupport<QJsonReaderImpl,QByteArray&> : BindNative {};
template<> struct BindSupport<QJsonReaderImpl, bool&> : BindNative {};
template<> struct BindSupport<QJsonReaderImpl, float&> : BindNative {};
......
......@@ -63,7 +63,7 @@ struct Person
.bind(firstName)
.bind(lastName)
.bind(height)
.bind(age) // TODO .any() // ignored
.bind(age) // .any() ignored
.bind(phones) // recursive calls to QBind will take care of that part
; // automagically closes all opened structures
}
......
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