geomconverter.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #include "geomconverter_p.h"
  2. #include "exception.h"
  3. #include "cborserializer.h"
  4. using namespace QtJsonSerializer;
  5. using namespace QtJsonSerializer::TypeConverters;
  6. bool GeomConverter::canConvert(int metaTypeId) const
  7. {
  8. static const QVector<int> types {
  9. QMetaType::QSize,
  10. QMetaType::QSizeF,
  11. QMetaType::QPoint,
  12. QMetaType::QPointF,
  13. QMetaType::QLine,
  14. QMetaType::QLineF,
  15. QMetaType::QRect,
  16. QMetaType::QRectF,
  17. };
  18. return types.contains(metaTypeId);
  19. }
  20. QList<QCborTag> GeomConverter::allowedCborTags(int metaTypeId) const
  21. {
  22. switch (metaTypeId) {
  23. case QMetaType::QSize:
  24. case QMetaType::QSizeF:
  25. return {static_cast<QCborTag>(CborSerializer::GeomSize)};
  26. case QMetaType::QPoint:
  27. case QMetaType::QPointF:
  28. return {static_cast<QCborTag>(CborSerializer::GeomPoint)};
  29. case QMetaType::QLine:
  30. case QMetaType::QLineF:
  31. return {static_cast<QCborTag>(CborSerializer::GeomLine)};
  32. case QMetaType::QRect:
  33. case QMetaType::QRectF:
  34. return {static_cast<QCborTag>(CborSerializer::GeomRect)};
  35. default:
  36. return {};
  37. }
  38. }
  39. QList<QCborValue::Type> GeomConverter::allowedCborTypes(int metaTypeId, QCborTag tag) const
  40. {
  41. Q_UNUSED(metaTypeId)
  42. Q_UNUSED(tag)
  43. return {QCborValue::Array};
  44. }
  45. int GeomConverter::guessType(QCborTag tag, QCborValue::Type dataType) const
  46. {
  47. if (dataType != QCborValue::Array)
  48. return QMetaType::UnknownType;
  49. switch (tag) {
  50. case static_cast<QCborTag>(CborSerializer::GeomSize):
  51. return QMetaType::QSizeF;
  52. case static_cast<QCborTag>(CborSerializer::GeomPoint):
  53. return QMetaType::QPointF;
  54. case static_cast<QCborTag>(CborSerializer::GeomLine):
  55. return QMetaType::QLineF;
  56. case static_cast<QCborTag>(CborSerializer::GeomRect):
  57. return QMetaType::QRectF;
  58. default:
  59. return QMetaType::UnknownType;
  60. }
  61. }
  62. QCborValue GeomConverter::serialize(int propertyType, const QVariant &value) const
  63. {
  64. switch (propertyType) {
  65. case QMetaType::QSize:
  66. return serializeSize(value.toSize());
  67. case QMetaType::QSizeF:
  68. return serializeSize(value.toSizeF());
  69. case QMetaType::QPoint:
  70. return serializePoint(value.toPoint());
  71. case QMetaType::QPointF:
  72. return serializePoint(value.toPointF());
  73. case QMetaType::QLine:
  74. return serializeLine(value.toLine());
  75. case QMetaType::QLineF:
  76. return serializeLine(value.toLineF());
  77. case QMetaType::QRect:
  78. return serializeRect(value.toRect());
  79. case QMetaType::QRectF:
  80. return serializeRect(value.toRectF());
  81. default:
  82. throw SerializationException{"Invalid type id"};
  83. }
  84. }
  85. QVariant GeomConverter::deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const
  86. {
  87. Q_UNUSED(parent)
  88. const auto array = (value.isTag() ? value.taggedValue() : value).toArray();
  89. switch (propertyType) {
  90. case QMetaType::QSize:
  91. return deserializeSize<QSize>(array);
  92. case QMetaType::QSizeF:
  93. return deserializeSize<QSizeF>(array);
  94. case QMetaType::QPoint:
  95. return deserializePoint<QPoint>(array);
  96. case QMetaType::QPointF:
  97. return deserializePoint<QPointF>(array);
  98. case QMetaType::QLine:
  99. return deserializeLine<QLine>(array);
  100. case QMetaType::QLineF:
  101. return deserializeLine<QLineF>(array);
  102. case QMetaType::QRect:
  103. return deserializeRect<QRect>(array);
  104. case QMetaType::QRectF:
  105. return deserializeRect<QRectF>(array);
  106. default:
  107. throw DeserializationException{"Invalid type id"};
  108. }
  109. }
  110. QCborValue GeomConverter::serializeSize(const std::variant<QSize, QSizeF> &size) const
  111. {
  112. return {
  113. static_cast<QCborTag>(CborSerializer::GeomSize),
  114. std::visit([](const auto &s) -> QCborArray {
  115. return {s.width(), s.height()};
  116. }, size)
  117. };
  118. }
  119. QCborValue GeomConverter::serializePoint(const std::variant<QPoint, QPointF> &point) const
  120. {
  121. return {
  122. static_cast<QCborTag>(CborSerializer::GeomPoint),
  123. std::visit([](const auto &p) -> QCborArray {
  124. return {p.x(), p.y()};
  125. }, point)
  126. };
  127. }
  128. QCborValue GeomConverter::serializeLine(const std::variant<QLine, QLineF> &line) const
  129. {
  130. return {
  131. static_cast<QCborTag>(CborSerializer::GeomLine),
  132. std::visit([this](const auto &l) -> QCborArray {
  133. return {
  134. helper()->serializeSubtype(qMetaTypeId<std::decay_t<decltype(l.p1())>>(), l.p1(), "p1"),
  135. helper()->serializeSubtype(qMetaTypeId<std::decay_t<decltype(l.p2())>>(), l.p2(), "p2")
  136. };
  137. }, line)
  138. };
  139. }
  140. QCborValue GeomConverter::serializeRect(const std::variant<QRect, QRectF> &rect) const
  141. {
  142. return {
  143. static_cast<QCborTag>(CborSerializer::GeomRect),
  144. std::visit([this](const auto &r) -> QCborArray {
  145. return {
  146. helper()->serializeSubtype(qMetaTypeId<std::decay_t<decltype(r.topLeft())>>(), r.topLeft(), "topLeft"),
  147. helper()->serializeSubtype(qMetaTypeId<std::decay_t<decltype(r.size())>>(), r.size(), "size")
  148. };
  149. }, rect)
  150. };
  151. }
  152. template<typename TSize>
  153. TSize GeomConverter::deserializeSize(const QCborArray &array) const
  154. {
  155. using TW = std::decay_t<decltype(TSize{}.width())>;
  156. using TH = std::decay_t<decltype(TSize{}.height())>;
  157. if (array.size() != 2)
  158. throw DeserializationException{"A size requires an array with exactly two numbers"};
  159. return {
  160. extract<TW>(array[0]),
  161. extract<TH>(array[1])
  162. };
  163. }
  164. template<typename TPoint>
  165. TPoint GeomConverter::deserializePoint(const QCborArray &array) const
  166. {
  167. using TX = std::decay_t<decltype(TPoint{}.x())>;
  168. using TY = std::decay_t<decltype(TPoint{}.y())>;
  169. if (array.size() != 2)
  170. throw DeserializationException{"A point requires an array with exactly two numbers"};
  171. return {
  172. extract<TX>(array[0]),
  173. extract<TY>(array[1])
  174. };
  175. }
  176. template<typename TLine>
  177. TLine GeomConverter::deserializeLine(const QCborArray &array) const
  178. {
  179. using TP1 = std::decay_t<decltype(TLine{}.p1())>;
  180. using TP2 = std::decay_t<decltype(TLine{}.p2())>;
  181. if (array.size() != 2)
  182. throw DeserializationException{"A line requires an array with exactly two points"};
  183. return {
  184. helper()->deserializeSubtype(qMetaTypeId<TP1>(), array[0], nullptr, "p1").template value<TP1>(),
  185. helper()->deserializeSubtype(qMetaTypeId<TP2>(), array[1], nullptr, "p2").template value<TP2>()
  186. };
  187. }
  188. template<typename TRect>
  189. TRect GeomConverter::deserializeRect(const QCborArray &array) const
  190. {
  191. using TTL = std::decay_t<decltype(TRect{}.topLeft())>;
  192. using TS = std::decay_t<decltype(TRect{}.size())>;
  193. if (array.size() != 2)
  194. throw DeserializationException{"A line requires an array with exactly two points"};
  195. return {
  196. helper()->deserializeSubtype(qMetaTypeId<TTL>(), array[0], nullptr, "topLeft").template value<TTL>(),
  197. helper()->deserializeSubtype(qMetaTypeId<TS>(), array[1], nullptr, "size").template value<TS>()
  198. };
  199. }
  200. template<>
  201. int GeomConverter::extract(const QCborValue &value) const
  202. {
  203. if (!value.isInteger())
  204. throw DeserializationException{"Expected integer, but got type " + QByteArray::number(value.type())};
  205. return static_cast<int>(value.toInteger());
  206. }
  207. template<>
  208. qreal GeomConverter::extract(const QCborValue &value) const
  209. {
  210. if (!value.isDouble() && !value.isInteger())
  211. throw DeserializationException{"Expected double, but got type " + QByteArray::number(value.type())};
  212. return value.toDouble();
  213. }