#include "geomconverter_p.h" #include "exception.h" #include "cborserializer.h" using namespace QtJsonSerializer; using namespace QtJsonSerializer::TypeConverters; bool GeomConverter::canConvert(int metaTypeId) const { static const QVector types { QMetaType::QSize, QMetaType::QSizeF, QMetaType::QPoint, QMetaType::QPointF, QMetaType::QLine, QMetaType::QLineF, QMetaType::QRect, QMetaType::QRectF, }; return types.contains(metaTypeId); } QList GeomConverter::allowedCborTags(int metaTypeId) const { switch (metaTypeId) { case QMetaType::QSize: case QMetaType::QSizeF: return {static_cast(CborSerializer::GeomSize)}; case QMetaType::QPoint: case QMetaType::QPointF: return {static_cast(CborSerializer::GeomPoint)}; case QMetaType::QLine: case QMetaType::QLineF: return {static_cast(CborSerializer::GeomLine)}; case QMetaType::QRect: case QMetaType::QRectF: return {static_cast(CborSerializer::GeomRect)}; default: return {}; } } QList GeomConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const { Q_UNUSED(metaTypeId) Q_UNUSED(tag) return {QCborValue::Array}; } int GeomConverter::guessType(QCborTag tag, QCborValue::Type dataType) const { if (dataType != QCborValue::Array) return QMetaType::UnknownType; switch (tag) { case static_cast(CborSerializer::GeomSize): return QMetaType::QSizeF; case static_cast(CborSerializer::GeomPoint): return QMetaType::QPointF; case static_cast(CborSerializer::GeomLine): return QMetaType::QLineF; case static_cast(CborSerializer::GeomRect): return QMetaType::QRectF; default: return QMetaType::UnknownType; } } QCborValue GeomConverter::serialize(int propertyType, const QVariant &value) const { switch (propertyType) { case QMetaType::QSize: return serializeSize(value.toSize()); case QMetaType::QSizeF: return serializeSize(value.toSizeF()); case QMetaType::QPoint: return serializePoint(value.toPoint()); case QMetaType::QPointF: return serializePoint(value.toPointF()); case QMetaType::QLine: return serializeLine(value.toLine()); case QMetaType::QLineF: return serializeLine(value.toLineF()); case QMetaType::QRect: return serializeRect(value.toRect()); case QMetaType::QRectF: return serializeRect(value.toRectF()); default: throw SerializationException{"Invalid type id"}; } } QVariant GeomConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const { Q_UNUSED(parent) const auto array = (value.isTag() ? value.taggedValue() : value).toArray(); switch (propertyType) { case QMetaType::QSize: return deserializeSize(array); case QMetaType::QSizeF: return deserializeSize(array); case QMetaType::QPoint: return deserializePoint(array); case QMetaType::QPointF: return deserializePoint(array); case QMetaType::QLine: return deserializeLine(array); case QMetaType::QLineF: return deserializeLine(array); case QMetaType::QRect: return deserializeRect(array); case QMetaType::QRectF: return deserializeRect(array); default: throw DeserializationException{"Invalid type id"}; } } QCborValue GeomConverter::serializeSize(const std::variant &size) const { return { static_cast(CborSerializer::GeomSize), std::visit([](const auto &s) -> QCborArray { return {s.width(), s.height()}; }, size) }; } QCborValue GeomConverter::serializePoint(const std::variant &point) const { return { static_cast(CborSerializer::GeomPoint), std::visit([](const auto &p) -> QCborArray { return {p.x(), p.y()}; }, point) }; } QCborValue GeomConverter::serializeLine(const std::variant &line) const { return { static_cast(CborSerializer::GeomLine), std::visit([this](const auto &l) -> QCborArray { return { helper()->serializeSubtype(qMetaTypeId>(), l.p1(), "p1"), helper()->serializeSubtype(qMetaTypeId>(), l.p2(), "p2") }; }, line) }; } QCborValue GeomConverter::serializeRect(const std::variant &rect) const { return { static_cast(CborSerializer::GeomRect), std::visit([this](const auto &r) -> QCborArray { return { helper()->serializeSubtype(qMetaTypeId>(), r.topLeft(), "topLeft"), helper()->serializeSubtype(qMetaTypeId>(), r.size(), "size") }; }, rect) }; } template TSize GeomConverter::deserializeSize(const QCborArray &array) const { using TW = std::decay_t; using TH = std::decay_t; if (array.size() != 2) throw DeserializationException{"A size requires an array with exactly two numbers"}; return { extract(array[0]), extract(array[1]) }; } template TPoint GeomConverter::deserializePoint(const QCborArray &array) const { using TX = std::decay_t; using TY = std::decay_t; if (array.size() != 2) throw DeserializationException{"A point requires an array with exactly two numbers"}; return { extract(array[0]), extract(array[1]) }; } template TLine GeomConverter::deserializeLine(const QCborArray &array) const { using TP1 = std::decay_t; using TP2 = std::decay_t; if (array.size() != 2) throw DeserializationException{"A line requires an array with exactly two points"}; return { helper()->deserializeSubtype(qMetaTypeId(), array[0], nullptr, "p1").template value(), helper()->deserializeSubtype(qMetaTypeId(), array[1], nullptr, "p2").template value() }; } template TRect GeomConverter::deserializeRect(const QCborArray &array) const { using TTL = std::decay_t; using TS = std::decay_t; if (array.size() != 2) throw DeserializationException{"A line requires an array with exactly two points"}; return { helper()->deserializeSubtype(qMetaTypeId(), array[0], nullptr, "topLeft").template value(), helper()->deserializeSubtype(qMetaTypeId(), array[1], nullptr, "size").template value() }; } template<> int GeomConverter::extract(const QCborValue &value) const { if (!value.isInteger()) throw DeserializationException{"Expected integer, but got type " + QByteArray::number(value.type())}; return static_cast(value.toInteger()); } template<> qreal GeomConverter::extract(const QCborValue &value) const { if (!value.isDouble() && !value.isInteger()) throw DeserializationException{"Expected double, but got type " + QByteArray::number(value.type())}; return value.toDouble(); }