metawriters.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. #include "metawriters.h"
  2. #include "metawriters_p.h"
  3. #include <QtCore/QRegularExpression>
  4. using namespace QtJsonSerializer;
  5. using namespace QtJsonSerializer::MetaWriters;
  6. using namespace QtJsonSerializer::MetaWriters::Implementations;
  7. Q_LOGGING_CATEGORY(QtJsonSerializer::MetaWriters::logSeqWriter, "qt.jsonserializer.metawriters.sequential")
  8. Q_LOGGING_CATEGORY(QtJsonSerializer::MetaWriters::logAsocWriter, "qt.jsonserializer.metawriters.associative")
  9. void SequentialWriter::registerWriter(int metaTypeId, SequentialWriterFactory *factory)
  10. {
  11. Q_ASSERT_X(factory, Q_FUNC_INFO, "factory must not be null!");
  12. QWriteLocker _{&MetaWritersPrivate::sequenceLock};
  13. MetaWritersPrivate::sequenceFactories.insert(metaTypeId, factory);
  14. MetaWritersPrivate::sequenceInfoCache.remove(metaTypeId);
  15. qCDebug(logSeqWriter) << "Added factory for type:" << QMetaTypeName(metaTypeId);
  16. }
  17. bool SequentialWriter::canWrite(int metaTypeId)
  18. {
  19. QReadLocker _{&MetaWritersPrivate::sequenceLock};
  20. return MetaWritersPrivate::sequenceFactories.contains(metaTypeId);
  21. }
  22. QSharedPointer<SequentialWriter> SequentialWriter::getWriter(QVariant &data)
  23. {
  24. QReadLocker _{&MetaWritersPrivate::sequenceLock};
  25. const auto factory = MetaWritersPrivate::sequenceFactories.value(data.userType());
  26. if (factory) {
  27. qCDebug(logSeqWriter) << "Found factory for data of type:" << QMetaTypeName(data.userType());
  28. return factory->create(data.data());
  29. } else {
  30. qCWarning(logSeqWriter) << "Unable to find factory for data of type:" << QMetaTypeName(data.userType());
  31. return {};
  32. }
  33. }
  34. SequentialWriter::SequenceInfo SequentialWriter::getInfo(int metaTypeId)
  35. {
  36. QReadLocker rLocker{&MetaWritersPrivate::sequenceLock};
  37. auto it = MetaWritersPrivate::sequenceInfoCache.find(metaTypeId);
  38. if (it != MetaWritersPrivate::sequenceInfoCache.end()) {
  39. qCDebug(logSeqWriter) << "Found SequenceInfo for type" << QMetaTypeName(metaTypeId)
  40. << "in cache";
  41. return *it;
  42. } else {
  43. rLocker.unlock();
  44. QWriteLocker wLocker{&MetaWritersPrivate::sequenceLock};
  45. const auto factory = MetaWritersPrivate::sequenceFactories.value(metaTypeId);
  46. if (factory) {
  47. qCDebug(logSeqWriter) << "Found factory to generate SequenceInfo for type:" << QMetaTypeName(metaTypeId);
  48. it = MetaWritersPrivate::sequenceInfoCache.insert(metaTypeId, factory->create(nullptr)->info());
  49. } else {
  50. qCWarning(logSeqWriter) << "Unable to find SequenceInfo for type" << QMetaTypeName(metaTypeId)
  51. << "- trying to guess by parsing the types name";
  52. it = MetaWritersPrivate::sequenceInfoCache.insert(metaTypeId, MetaWritersPrivate::tryParseSequenceInfo(metaTypeId));
  53. }
  54. return *it;
  55. }
  56. }
  57. SequentialWriter::~SequentialWriter() = default;
  58. SequentialWriter::SequentialWriter() = default;
  59. SequentialWriterFactory::SequentialWriterFactory() = default;
  60. SequentialWriterFactory::~SequentialWriterFactory() = default;
  61. void AssociativeWriter::registerWriter(int metaTypeId, AssociativeWriterFactory *factory)
  62. {
  63. Q_ASSERT_X(factory, Q_FUNC_INFO, "factory must not be null!");
  64. QWriteLocker _{&MetaWritersPrivate::associationLock};
  65. MetaWritersPrivate::associationFactories.insert(metaTypeId, factory);
  66. MetaWritersPrivate::associationInfoCache.remove(metaTypeId);
  67. qCDebug(logAsocWriter) << "Added factory for type:" << QMetaTypeName(metaTypeId);
  68. }
  69. bool AssociativeWriter::canWrite(int metaTypeId)
  70. {
  71. QReadLocker _{&MetaWritersPrivate::associationLock};
  72. return MetaWritersPrivate::associationFactories.contains(metaTypeId);
  73. }
  74. QSharedPointer<AssociativeWriter> AssociativeWriter::getWriter(QVariant &data)
  75. {
  76. QReadLocker _{&MetaWritersPrivate::associationLock};
  77. const auto factory = MetaWritersPrivate::associationFactories.value(data.userType());
  78. if (factory) {
  79. qCDebug(logAsocWriter) << "Found factory for data of type:" << QMetaTypeName(data.userType());
  80. return factory->create(data.data());
  81. } else {
  82. qCWarning(logAsocWriter) << "Unable to find factory for data of type:" << QMetaTypeName(data.userType());
  83. return {};
  84. }
  85. }
  86. AssociativeWriter::AssociationInfo AssociativeWriter::getInfo(int metaTypeId)
  87. {
  88. QReadLocker rLocker{&MetaWritersPrivate::associationLock};
  89. auto it = MetaWritersPrivate::associationInfoCache.find(metaTypeId);
  90. if (it != MetaWritersPrivate::associationInfoCache.end()) {
  91. qCDebug(logAsocWriter) << "Found SequenceInfo for type" << QMetaTypeName(metaTypeId)
  92. << "in cache";
  93. return *it;
  94. } else {
  95. rLocker.unlock();
  96. QWriteLocker wLocker{&MetaWritersPrivate::associationLock};
  97. const auto factory = MetaWritersPrivate::associationFactories.value(metaTypeId);
  98. if (factory) {
  99. qCDebug(logAsocWriter) << "Found factory to generate SequenceInfo for type:" << QMetaTypeName(metaTypeId);
  100. it = MetaWritersPrivate::associationInfoCache.insert(metaTypeId, factory->create(nullptr)->info());
  101. } else {
  102. qCWarning(logAsocWriter) << "Unable to find SequenceInfo for type" << QMetaTypeName(metaTypeId)
  103. << "- trying to guess by parsing the types name";
  104. it = MetaWritersPrivate::associationInfoCache.insert(metaTypeId, MetaWritersPrivate::tryParseAssociationInfo(metaTypeId));
  105. }
  106. return *it;
  107. }
  108. }
  109. AssociativeWriter::~AssociativeWriter() = default;
  110. AssociativeWriter::AssociativeWriter() = default;
  111. AssociativeWriterFactory::AssociativeWriterFactory() = default;
  112. AssociativeWriterFactory::~AssociativeWriterFactory() = default;
  113. SequentialWriterImpl<QList, QVariant>::SequentialWriterImpl(QVariantList *data)
  114. : _data{data}
  115. {}
  116. SequentialWriter::SequenceInfo SequentialWriterImpl<QList, QVariant>::info() const
  117. {
  118. return {QMetaType::UnknownType, false};
  119. }
  120. void SequentialWriterImpl<QList, QVariant>::reserve(int size)
  121. {
  122. _data->reserve(size);
  123. }
  124. void SequentialWriterImpl<QList, QVariant>::add(const QVariant &value)
  125. {
  126. _data->append(value);
  127. }
  128. AssociativeWriterImpl<QMap, QString, QVariant>::AssociativeWriterImpl(QVariantMap *data)
  129. : _data{data}
  130. {}
  131. AssociativeWriter::AssociationInfo AssociativeWriterImpl<QMap, QString, QVariant>::info() const
  132. {
  133. return {QMetaType::QString, QMetaType::UnknownType};
  134. }
  135. void AssociativeWriterImpl<QMap, QString, QVariant>::add(const QVariant &key, const QVariant &value)
  136. {
  137. _data->insert(key.toString(), value);
  138. }
  139. AssociativeWriterImpl<QHash, QString, QVariant>::AssociativeWriterImpl(QVariantHash *data)
  140. : _data{data}
  141. {}
  142. AssociativeWriter::AssociationInfo AssociativeWriterImpl<QHash, QString, QVariant>::info() const
  143. {
  144. return {QMetaType::QString, QMetaType::UnknownType};
  145. }
  146. void AssociativeWriterImpl<QHash, QString, QVariant>::add(const QVariant &key, const QVariant &value)
  147. {
  148. _data->insert(key.toString(), value);
  149. }
  150. // ------------- private implementation -------------
  151. QReadWriteLock MetaWritersPrivate::sequenceLock;
  152. QHash<int, SequentialWriterFactory*> MetaWritersPrivate::sequenceFactories {
  153. {QMetaType::QStringList, new SequentialWriterFactoryQStringList{}},
  154. {QMetaType::QByteArrayList, new SequentialWriterFactoryQByteArrayList{}},
  155. {QMetaType::QVariantList, new SequentialWriterFactoryQVariantList{}}
  156. };
  157. QHash<int, SequentialWriter::SequenceInfo> MetaWritersPrivate::sequenceInfoCache;
  158. QReadWriteLock MetaWritersPrivate::associationLock;
  159. QHash<int, AssociativeWriterFactory*> MetaWritersPrivate::associationFactories {
  160. {QMetaType::QVariantMap, new AssociativeWriterFactoryQVariantMap{}},
  161. {QMetaType::QVariantHash, new AssociativeWriterFactoryQVariantHash{}}
  162. };
  163. QHash<int, AssociativeWriter::AssociationInfo> MetaWritersPrivate::associationInfoCache;
  164. SequentialWriter::SequenceInfo MetaWritersPrivate::tryParseSequenceInfo(int metaTypeId)
  165. {
  166. if (metaTypeId == QMetaType::QStringList)
  167. return {QMetaType::QString, false};
  168. else if (metaTypeId == QMetaType::QByteArrayList)
  169. return {QMetaType::QByteArray, false};
  170. else if (metaTypeId == QMetaType::QVariantList)
  171. return {QMetaType::UnknownType, false};
  172. else {
  173. static const QRegularExpression listTypeRegex{
  174. QStringLiteral(R"__(^((?![0-9_])(?:\w|::)*\w)\s*<\s*(.*?)\s*>$)__"),
  175. QRegularExpression::UseUnicodePropertiesOption
  176. };
  177. auto match = listTypeRegex.match(QString::fromUtf8(QMetaTypeName(metaTypeId)));
  178. if (match.hasMatch()) {
  179. return {
  180. #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
  181. QMetaType::type(match.captured(2).toUtf8().trimmed()),
  182. #else
  183. QMetaType::fromName(match.captured(2).toUtf8().trimmed()).id(),
  184. #endif
  185. match.captured(1) == QStringLiteral("QSet")
  186. };
  187. }
  188. }
  189. return {QMetaType::UnknownType, false};
  190. }
  191. AssociativeWriter::AssociationInfo MetaWritersPrivate::tryParseAssociationInfo(int metaTypeId)
  192. {
  193. if (metaTypeId == QMetaType::QVariantMap ||
  194. metaTypeId == QMetaType::QVariantHash)
  195. return {QMetaType::QString, QMetaType::UnknownType};
  196. else {
  197. static const QRegularExpression mapTypeRegex{
  198. QStringLiteral(R"__(^(?![0-9_])(?:\w|::)*\w\s*<\s*(.*?)\s*>$)__"),
  199. QRegularExpression::UseUnicodePropertiesOption
  200. };
  201. auto match = mapTypeRegex.match(QString::fromUtf8(QMetaTypeName(metaTypeId)));
  202. if (match.hasMatch()) {
  203. // parse match, using <> and , rules
  204. const auto matchStr = match.captured(1);
  205. auto bCount = 0;
  206. for (auto i = 0; i < matchStr.size(); ++i) {
  207. const auto &c = matchStr[i];
  208. if (c == QLatin1Char('<'))
  209. ++bCount;
  210. else if (c == QLatin1Char('>'))
  211. --bCount;
  212. else if (bCount == 0 && c == QLatin1Char(',')) {
  213. #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
  214. return {
  215. QMetaType::type(matchStr.mid(0, i).trimmed().toUtf8()),
  216. QMetaType::type(matchStr.mid(i + 1).trimmed().toUtf8())
  217. };
  218. #else
  219. return {
  220. QMetaType::fromName(matchStr.mid(0, i).trimmed().toUtf8()).id(),
  221. QMetaType::fromName(matchStr.mid(i + 1).trimmed().toUtf8()).id()
  222. };
  223. #endif
  224. }
  225. }
  226. }
  227. }
  228. return {QMetaType::UnknownType, QMetaType::UnknownType};
  229. }