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 043ac220 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

illustrate serialization options with QColor type that is made

compatible with QDataStream at runtime while being more explicit with
other IBind
parent 71eb27b9
......@@ -94,9 +94,11 @@ static QName qBindIgnoredBytes = "Ignored bytes" ;
#include <QtCore/qstring.h>
//! QMetaData is data about current data (e.g. tag, attribute, style, etc.)
//! QMetaData is optional data about current data to enable optimized processing (e.g. tag, , style, etc.) and/or transmission (QAbstractItemModel headers, CBOR tags, XML attribute, CSS, numpy.ndarray shapes, etc.)
using QMetaData = std::map<QName,QString>;
static const char* qmDataStreamVersion = "qmDataStreamVersion"; //!< Allows IBind support of QDataStream
// N-dimensional data structures for which specific IWriter may have optimized implementations
// BEWARE though that nested calls to IWriter are not guaranteed to follow the declared structure (this would prevent reusing general QBind functors for nested data structures)
......@@ -906,6 +908,8 @@ struct QBind<QList<T>, TResult> {
#include <QtCore/qmap.h>
// TODO QBind<QMap<TKey,T>,_> with meta({qmColumns,"key,value"}).sequence().record().bind("key",i.key()).bind("value",i.value())
template<typename T, class TResult> //=Cursor
struct QBind<QMap<QString,T>, TResult> {
static TResult bind(Val<TResult>&& v, QMap<QString,T>&& ts) {
......@@ -937,22 +941,6 @@ struct QBind<QMap<QString,T>, TResult> {
}
};
#include <QtGui/qcolor.h>
template<>
struct QBind<QColor> {
static Cursor bind(Val<Cursor>&& v, QColor&& src) {
return v.record()
.bind("A",src.alpha())
.bind("R",src.red ())
.bind("G",src.green())
.bind("B",src.blue ());
}
static Cursor bind(Val<Cursor>&& v, QColor& src) {
return bind(std::move(v),QColor(src));
}
};
// --------------------------------------------------------------------------
// QBind<Val<Cursor>> for the set of IBind's BindNative types
......
......@@ -100,7 +100,7 @@ enum {
// //////////////////////////////////////////////////////////////////////////
// QBind<T,QCbor*> support
class QCborWriter : public IWriter
class QCborWriter : public IWriter // TODO Support CBOR tags for IBind BindNative types and multi-dimensional QMetaData (e.g. support qmColumns with http://cbor.schmorp.de/stringref, qmSizes with https://datatracker.ietf.org/doc/draft-ietf-cbor-array-tags/?include_text=1 )
{
Q_DISABLE_COPY(QCborWriter)
public:
......
......@@ -47,15 +47,11 @@
#include "QBind_impl.h"
// //////////////////////////////////////////////////////////////////////////
// QBind<T,QDataStream*> support using operator<< for all registered types and containers, or GenericBind with DataTag
// QBind<T,QDataStream*> support
static const char* qmDataStreamVersion = "qmDataStreamVersion";
//! \warning As with QDataStream, QDataWriter and QDataReader must:
//! - bind the same C++ root data type (when unknown, QVariant can be used on both side)
//! - use the same set of registered QMetaTypeIds with operator<< defined
//! - use compatible ByteOrder, FloatingPointPrecision, and Version
class QDataWriter : public IWriter // allows runtime flexibility without BindNative support for QColor
//! \warning As with QDataStream, QDataWriter and QDataReader must bind compatible C++ data types, and QDataStream ByteOrder, FloatingPointPrecision and Version
//! \remark When not statically known, such information can be transmitted using meta({{"type",...}}) although some IBind implementations may not support it
class QDataWriter : public IWriter // allows runtime flexibility but requires QBind<T> in addition to T::operator<<(QDebug&) and does not warrant QDataStream operators compatibility if QBind<T> ignores qmDataStreamVersion in meta(QMetaData&)
{
Q_DISABLE_COPY(QDataWriter)
public:
......@@ -77,7 +73,7 @@ protected:
bool _null ( ) { *io << nullptr; return true; }
bool _bind ( const char* s) { QByteArray ba = QByteArray::fromRawData(s, int(qstrlen(s))); return _bind(ba); }
template<typename T>
bool _bind ( T&& t) { *io << t; return true; } // Use QVariant to explicit the parts that may be unknown to the reader
bool _bind ( T&& t) { *io << t; return true; }
bool _isOk() noexcept { return io && io->status()==QDataStream::Ok; }
......@@ -91,38 +87,14 @@ private:
QDataStream* io;
QString version;
};
template<typename T> struct BindSupport<T,QDataWriter> : BindSupport<T> {};
// TODO BindNative other types that should bind specifically for compatibility with QDataStream
template<typename T> struct BindSupport<T ,QDataWriter> : BindNative {}; //!< \remark Use meta() or QVariant to encapsulate Ts that are not statically known (provided qRegisterMetaType<T>() and qRegisterMetaTypeStreamOperators<T>() are called)
template<> struct BindSupport<QColor,QDataWriter> : BindNative {};
// TODO BindNative other types that should bind specifically for compatibility with QDataStream
// --------------------------------------------------------------------------
// Providing a general QDataReader may be deceiving because the QDataStream structure is implicit:
// A reader is assumed to specify exactly what to read based on the stream origin and version
// QVariant could be used though for parts which type are not known in advance such as the exact type of a message coming from a socket
// And QDataStream version can be
// ///////////////////////////////////////////////////////////////////////////
// QBind<T,Cur<QDataWriter>> types that should bind specifically for compatibility with QDataStream
template<>
struct QBind<QColor, Cur<QDataWriter>> {
static Cur<QDataWriter> bind(Val<Cur<QDataWriter>>&& v, QColor&& src) {
QMetaData m;
v=v.meta(m);
if (m[qmDataStreamVersion].toInt()<7) {
v->reportError("Unsupported QDataStream.version()");
return v.null();
}
return v.sequence()
.bind(quint8 (src.spec ()))
.bind(quint16(src.alpha()))
.bind(quint16(src.red ()))
.bind(quint16(src.green()))
.bind(quint16(src.blue ()));
}
static Cur<QDataWriter> bind(Val<Cur<QDataWriter>>&& v, QColor& src) {
return bind(std::move(v),QColor(src));
}
};
// TODO QDataReader
// \remark Providing a general QDataReader may be deceiving because the QDataStream structure is implicit, thus
// a reader is usually assumed to statically know the data type to read based on the stream origin and version.
// Though QVariant can be used for parts which type are not statically known though, such as the dynamic type of a message coming from a socket.
// Finally, QDataStream version can be retrieved from meta(QMetaData&) to adapt to data schema changes over the time \see QBind<QColor> for an example
......@@ -110,6 +110,44 @@ QDataStream &operator>>(QDataStream &in, Person &p)
>> p.children;
}
// //////////////////////////////////////////////////////////////////////////
// QBind<T,_> example using an external bind method and special support for QDataStream using QMetaData
#include <QtGui/qcolor.h>
template<>
struct QBind<QColor> {
static Cursor bind(Val<Cursor>&& v, QColor&& src) {
QMetaData m;
v=v.meta(m);
auto dataStreamVersion = m.find(qmDataStreamVersion);
if (dataStreamVersion!=m.end()) {
if (dataStreamVersion->second.toInt()<7) { v->reportError("Unsupported QDataStream.version()");
return v.null();
}
return v.sequence().bind(qint8(src.spec())).bind(quint16(src.alpha())).bind(quint16(src.cyan())).bind(quint16(src.magenta())).bind(quint16(src.yellow())).bind(quint16(src.black()));
}
if (!src.isValid()) {
return v.null();
}
Rec<Cursor> r = v.record();
switch(src.spec()) {
case QColor::Spec::Rgb : r = r.sequence("RGB" ).bind(quint8(src.red ())).bind(quint8(src.green ())).bind(quint8(src.blue ())) .out(); break;
case QColor::Spec::Hsl : r = r.sequence("HSL" ).bind(qint16(src.hslHue())).bind(quint8(src.hslSaturation())).bind(quint8(src.lightness())) .out(); break;
case QColor::Spec::Hsv : r = r.sequence("HSV" ).bind(qint16(src.hsvHue())).bind(quint8(src.hsvSaturation())).bind(quint8(src.value ())) .out(); break;
case QColor::Spec::Cmyk: r = r.sequence("CMYK" ).bind(quint8(src.cyan ())).bind(quint8(src.magenta ())).bind(quint8(src.yellow ())).bind(quint8(src.black())).out(); break;
default: Q_ASSERT(false);
}
if (src.alpha()<255) { r = r.bind("alpha",src.alpha()); }
return r.bind("base",quint8(255)); // Explicits ARGBCMYKSLV components' base (H base is 360 corresponding to color wheel degrees, with -1 used for gray in addition to S being 0)
// QDebug use of float values removes need for base but may lose precision
}
static Cursor bind(Val<Cursor>&& v, QColor& src) {
return bind(std::move(v),QColor(src));
}
};
// //////////////////////////////////////////////////////////////////////////
// IBind basic implementation example
......@@ -277,10 +315,13 @@ int main(int argc, char *argv[])
s.append(ascii);
s.append(false);
s.startMap();
s.append("A");s.append(color.alpha());
s.append("R");s.append(color.red());
s.append("G");s.append(color.green());
s.append("B");s.append(color.blue());
s.append("RGB");
s.startArray();
s.append(quint8(color.red ()));
s.append(quint8(color.green()));
s.append(quint8(color.blue ()));
s.endArray();
s.append("base"); s.append(quint8(255));
s.endMap();
s.endArray();
}
......
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