// Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2019 Alexey Edelev // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QPROTOBUFSERIALIZER_H #define QPROTOBUFSERIALIZER_H #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace QtProtobufPrivate { class QProtobufSelfcheckIterator; } // namespace QtProtobufPrivate class QProtobufSerializerPrivate; class Q_PROTOBUF_EXPORT QProtobufSerializer : public QAbstractProtobufSerializer { Q_DISABLE_COPY_MOVE(QProtobufSerializer) public: QProtobufSerializer(); ~QProtobufSerializer() override; QProtobufSerializer::DeserializationError deserializationError() const override; QString deserializationErrorString() const override; QByteArray serializeMessage(const QProtobufMessage *message, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering) const override; bool deserializeMessage(QProtobufMessage *message, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, QByteArrayView data) const override; QByteArray serializeObject(const QProtobufMessage *message, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const; bool deserializeObject(QProtobufMessage *message, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, QtProtobufPrivate::QProtobufSelfcheckIterator &it) const; QByteArray serializeListObject(const QProtobufMessage *message, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const; bool deserializeListObject(QProtobufMessage *message, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, QtProtobufPrivate::QProtobufSelfcheckIterator &it) const; QByteArray serializeMapPair(const QVariant &key, const QVariant &value, const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const; bool deserializeMapPair(QVariant &key, QVariant &value, QtProtobufPrivate::QProtobufSelfcheckIterator &it) const; QByteArray serializeEnum(QtProtobuf::int64 value, const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const; QByteArray serializeEnumList(const QList &value, const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const; Q_REQUIRED_RESULT bool deserializeEnum(QtProtobuf::int64 &value, QtProtobufPrivate::QProtobufSelfcheckIterator &it) const; Q_REQUIRED_RESULT bool deserializeEnumList(QList &value, QtProtobufPrivate::QProtobufSelfcheckIterator &it) const; private: std::unique_ptr d_ptr; }; namespace QtProtobufPrivate { //! \private [[maybe_unused]] constexpr int NotUsedFieldIndex = -1; using Serializer = void (*)(const QProtobufSerializer *, const QVariant &, const QProtobufPropertyOrderingInfo &, QByteArray &); using Deserializer = void (*)(const QProtobufSerializer *, QProtobufSelfcheckIterator &, QVariant &); /*! \private \brief SerializationHandlers contains set of objects that required for class serialization/deserialization */ struct SerializationHandler { Serializer serializer = nullptr; /*!< serializer assigned to class */ Deserializer deserializer = nullptr; /*!< deserializer assigned to class */ }; extern Q_PROTOBUF_EXPORT SerializationHandler findHandler(QMetaType type); extern Q_PROTOBUF_EXPORT void registerHandler(QMetaType type, const SerializationHandler &handlers); /*! \private \brief default serializer template for type T that inherits from QProtobufMessage */ template::value, int> = 0> void serializeObject(const QProtobufSerializer *serializer, const QVariant &value, const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); buffer.append(serializer->serializeObject(value.value(), T::propertyOrdering, fieldInfo)); } /*! \private \brief default serializer template for list of type T objects that inherits from QProtobufMessage */ template::value, int> = 0> void serializeList(const QProtobufSerializer *serializer, const QVariant &listValue, const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); QList> list = listValue.value>>(); for (auto &value : list) { if (!value) { continue; } buffer.append(serializer->serializeListObject(value.get(), V::propertyOrdering, fieldInfo)); } } /*! \private \brief default serializer template for map of key K, value V */ template::value, int> = 0> void serializeMap(const QProtobufSerializer *serializer, const QVariant &value, const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); QHash mapValue = value.value>(); for (auto it = mapValue.constBegin(); it != mapValue.constEnd(); it++) { buffer.append(serializer->serializeMapPair(QVariant::fromValue(it.key()), QVariant::fromValue(it.value()), fieldInfo)); } } /*! \private \brief default serializer template for map of type key K, value V. Specialization for V that inherits from QProtobufMessage */ template::value, int> = 0> void serializeMap(const QProtobufSerializer *serializer, const QVariant &value, const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); QHash> mapValue = value.value>>(); for (auto it = mapValue.constBegin(); it != mapValue.constEnd(); it++) { if (it.value() == nullptr) continue; buffer.append(serializer->serializeMapPair(QVariant::fromValue(it.key()), QVariant::fromValue(it.value().get()), fieldInfo)); } } /*! \private \brief default serializer template for enum types */ template::value, int> = 0> void serializeEnum(const QProtobufSerializer *serializer, const QVariant &value, const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); buffer.append(serializer->serializeEnum(QtProtobuf::int64(value.value()), fieldInfo)); } /*! \private \brief default serializer template for enum list types */ template::value, int> = 0> void serializeEnumList(const QProtobufSerializer *serializer, const QVariant &value, const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); QList intList; for (auto enumValue : value.value>()) { intList.append(QtProtobuf::int64(enumValue)); } buffer.append(serializer->serializeEnumList(intList, fieldInfo)); } /*! \private \brief default deserializer template for type T that inherits from QProtobufMessage */ template::value, int> = 0> void deserializeObject(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, QVariant &to) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); auto value = std::make_unique(); if (serializer->deserializeObject(value.get(), T::propertyOrdering, it)) to = QVariant::fromValue(value.release()); } /*! \private \brief default deserializer template for list of type T objects that inherits from QProtobufMessage */ template::value, int> = 0> void deserializeList(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, QVariant &previous) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); auto newValue = std::make_shared(); QList> list = previous.value>>(); if (serializer->deserializeListObject(newValue.get(), V::propertyOrdering, it)) { list.append(std::move(newValue)); previous.setValue(list); } } /*! \private * \brief default deserializer template for map of key K, value V */ template::value, int> = 0> void deserializeMap(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, QVariant &previous) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); QHash out = previous.value>(); QVariant key = QVariant::fromValue(K()); QVariant value = QVariant::fromValue(V()); if (serializer->deserializeMapPair(key, value, it)) { out[key.value()] = value.value(); previous = QVariant::fromValue>(out); } } /*! \private * \brief default deserializer template for map of type key K, value V. Specialization for V that inherits from QProtobufMessage */ template::value, int> = 0> void deserializeMap(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, QVariant &previous) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); auto out = previous.value>>(); QVariant key = QVariant::fromValue(K()); QVariant value = QVariant::fromValue(nullptr); if (serializer->deserializeMapPair(key, value, it)) { out[key.value()] = std::shared_ptr(value.value()); previous = QVariant::fromValue>>(out); } } /*! \private * \brief default deserializer template for enum type T */ template::value, int> = 0> void deserializeEnum(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, QVariant &to) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); QtProtobuf::int64 intValue; if (serializer->deserializeEnum(intValue, it)) to = QVariant::fromValue(static_cast(intValue._t)); } /*! \private * \brief default deserializer template for enumList type T */ template::value, int> = 0> void deserializeEnumList(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, QVariant &previous) { Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); QList intList; if (!serializer->deserializeEnumList(intList, it)) return; QList enumList = previous.value>(); for (auto intValue : intList) enumList.append(static_cast(intValue._t)); previous = QVariant::fromValue>(enumList); } } // namespace QtProtobufPrivate template inline void qRegisterProtobufType() { T::registerTypes(); QtProtobufPrivate::registerOrdering(QMetaType::fromType(), T::propertyOrdering); QtProtobufPrivate::registerHandler( QMetaType::fromType(), { QtProtobufPrivate::serializeObject, QtProtobufPrivate::deserializeObject }); QtProtobufPrivate::registerHandler( QMetaType::fromType>>(), { QtProtobufPrivate::serializeList, QtProtobufPrivate::deserializeList }); } #ifdef Q_QDOC template inline void qRegisterProtobufMapType(); #else // !Q_QDOC template::value, int> = 0> inline void qRegisterProtobufMapType() { QtProtobufPrivate::registerHandler( QMetaType::fromType>(), { QtProtobufPrivate::serializeMap, QtProtobufPrivate::deserializeMap }); } #endif // Q_QDOC #ifdef Q_QDOC template inline void qRegisterProtobufMapType(); #else // !Q_QDOC template::value, int> = 0> inline void qRegisterProtobufMapType() { QtProtobufPrivate::registerHandler( QMetaType::fromType>>(), { QtProtobufPrivate::serializeMap, QtProtobufPrivate::deserializeMap }); } #endif // Q_QDOC #ifdef Q_QDOC template inline void qRegisterProtobufEnumType(); #else // !Q_QDOC template::value, int> = 0> inline void qRegisterProtobufEnumType() { QtProtobufPrivate::registerHandler( QMetaType::fromType(), { QtProtobufPrivate::serializeEnum, QtProtobufPrivate::deserializeEnum }); QtProtobufPrivate::registerHandler( QMetaType::fromType>(), { QtProtobufPrivate::serializeEnumList, QtProtobufPrivate::deserializeEnumList }); } #endif // Q_QDOC QT_END_NAMESPACE #endif // QPROTOBUFSERIALIZER_H