mirror of https://github.com/qt/qtgrpc.git
Make the protobuf serializer registry private
Change the serializing mechanism that is used to serialize protobuf repeated and map fields. We used the serializer registry to serialize and deserialize repeated and map fields, which exposed the registry as public API and was quite ugly. Meanwhile QMetaType allows to register the mutable zero-copy converter and access meta-type the special way we want, using QMetaType::registerMutableView. This introduces QProtobufRepeatedIterator, special class that allows accessing and adding new elements to the protobuf repeated and map fields, that are represented as QList<T> and QHash<K, V> respectively. Register the mutable view to this new class for all related classes. QProtobufRepeatedIterator is a wrapper around QtProtobufPrivate::AbstractRepeatedIterator interface and manages the allocated AbstractRepeatedIterator implementation. QtProtobufPrivate::AbstractRepeatedIterator got two implementations for QList and QHash. The serializer registry is moved to private API but stil can be and is used to customize the serialization using the proxies. [ChangeLog][Protobuf] QtProtobufPrivate::SerializationHandler, QtProtobufPrivate::registerHandler and related functionality are now private API. [ChangeLog][Protobuf] Added QProtobufRepeatedIterator. QVariant that contain repeated or map protobuf values can be converted to this class using QVariant::view method. Pick-to: 6.8 Task-number: QTBUG-123626 Change-Id: I282318e82596839ff436bb33a1bed5f3474488fd Reviewed-by: Dennis Oberst <dennis.oberst@qt.io>
This commit is contained in:
parent
334911cdea
commit
61ccc3f82f
|
|
@ -13,6 +13,7 @@ qt_internal_add_module(Protobuf
|
|||
qprotobufpropertyordering.cpp qprotobufpropertyordering.h
|
||||
qprotobufpropertyorderingbuilder_p.h
|
||||
qprotobufregistration.cpp qprotobufregistration.h qprotobufregistration_p.h
|
||||
qprotobufrepeatediterator.cpp qprotobufrepeatediterator.h
|
||||
qprotobufselfcheckiterator_p.h
|
||||
qprotobufserializer.cpp qprotobufserializer.h qprotobufserializer_p.h
|
||||
qtprotobufdefs_p.h
|
||||
|
|
|
|||
|
|
@ -261,8 +261,7 @@ public:
|
|||
return {};
|
||||
}
|
||||
|
||||
void serializeProperty(const QVariant &propertyValue,
|
||||
const QProtobufFieldInfo &fieldInfo)
|
||||
void serializeProperty(QVariant propertyValue, const QProtobufFieldInfo &fieldInfo)
|
||||
{
|
||||
QMetaType metaType = propertyValue.metaType();
|
||||
auto userType = propertyValue.userType();
|
||||
|
|
@ -281,6 +280,26 @@ public:
|
|||
}
|
||||
|
||||
const auto fieldFlags = fieldInfo.fieldFlags();
|
||||
|
||||
if (propertyValue.canView(QMetaType::fromType<QProtobufRepeatedIterator>())) {
|
||||
QProtobufRepeatedIterator propertyIt = propertyValue.view<QProtobufRepeatedIterator>();
|
||||
if (fieldFlags & QtProtobufPrivate::FieldFlag::Repeated
|
||||
&& !(fieldFlags & QtProtobufPrivate::FieldFlag::Enum)) {
|
||||
const auto fieldName = fieldInfo.jsonName().toString();
|
||||
QJsonObject activeObject = activeValue.toObject();
|
||||
activeValue = activeObject.value(fieldName).toArray();
|
||||
while (propertyIt.hasNext())
|
||||
serializeObject(&propertyIt.next(), fieldInfo);
|
||||
if (!activeValue.toArray().empty())
|
||||
activeObject.insert(fieldName, activeValue);
|
||||
activeValue = activeObject;
|
||||
} else {
|
||||
while (propertyIt.hasNext())
|
||||
serializeObject(&propertyIt.next(), fieldInfo);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (fieldFlags & QtProtobufPrivate::FieldFlag::Enum) {
|
||||
QJsonObject activeObject = activeValue.toObject();
|
||||
if (fieldFlags & QtProtobufPrivate::FieldFlag::Repeated) {
|
||||
|
|
@ -301,25 +320,12 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
auto serializerFunction = [this](const QProtobufMessage *message,
|
||||
const QProtobufFieldInfo &fieldInfo) {
|
||||
this->serializeObject(message, fieldInfo);
|
||||
};
|
||||
|
||||
auto handler = QtProtobufPrivate::findHandler(metaType);
|
||||
if (handler.serializer) {
|
||||
if (fieldFlags & QtProtobufPrivate::FieldFlag::Repeated
|
||||
&& !(fieldFlags & QtProtobufPrivate::FieldFlag::Enum)) {
|
||||
const auto fieldName = fieldInfo.jsonName().toString();
|
||||
QJsonObject activeObject = activeValue.toObject();
|
||||
activeValue = activeObject.value(fieldName).toArray();
|
||||
handler.serializer(serializerFunction, propertyValue.constData(), fieldInfo);
|
||||
if (!activeValue.toArray().empty())
|
||||
activeObject.insert(fieldName, activeValue);
|
||||
activeValue = activeObject;
|
||||
} else {
|
||||
handler.serializer(serializerFunction, propertyValue.constData(), fieldInfo);
|
||||
}
|
||||
handler.serializer([this](const QProtobufMessage *message,
|
||||
const QProtobufFieldInfo &
|
||||
fieldInfo) { this->serializeObject(message, fieldInfo); },
|
||||
propertyValue.constData(), fieldInfo);
|
||||
} else {
|
||||
QJsonObject activeObject = activeValue.toObject();
|
||||
auto iter = handlers.constFind(userType);
|
||||
|
|
@ -519,11 +525,8 @@ public:
|
|||
return propertyData;
|
||||
}
|
||||
|
||||
auto handler = QtProtobufPrivate::findHandler(metaType);
|
||||
if (handler.deserializer) {
|
||||
auto deserializerFunction = [this](QProtobufMessage *message) {
|
||||
return this->deserializeObject(message);
|
||||
};
|
||||
if (propertyData.canView(QMetaType::fromType<QProtobufRepeatedIterator>())) {
|
||||
QProtobufRepeatedIterator propertyIt = propertyData.view<QProtobufRepeatedIterator>();
|
||||
if (activeValue.isArray()) {
|
||||
QJsonArray array = activeValue.toArray();
|
||||
if (array.isEmpty()) {
|
||||
|
|
@ -531,26 +534,35 @@ public:
|
|||
activeValue = {};
|
||||
return propertyData;
|
||||
}
|
||||
if (!array.at(0).isObject()) { // Enum array
|
||||
handler.deserializer(deserializerFunction, propertyData.data());
|
||||
ok = propertyData.isValid();
|
||||
} else {
|
||||
while (!array.isEmpty() &&
|
||||
deserializationError == QAbstractProtobufSerializer::NoError) {
|
||||
activeValue = array.takeAt(0);
|
||||
handler.deserializer(deserializerFunction, propertyData.data());
|
||||
}
|
||||
ok = propertyData.isValid();
|
||||
}
|
||||
} else {
|
||||
// We should attempt deserializing property while the active value !isNull.
|
||||
// This is required to deserialize the map fields.
|
||||
while (!activeValue.isNull()
|
||||
|
||||
while (!array.isEmpty()
|
||||
&& deserializationError == QAbstractProtobufSerializer::NoError) {
|
||||
handler.deserializer(deserializerFunction, propertyData.data());
|
||||
activeValue = array.takeAt(0);
|
||||
if (deserializeObject(&propertyIt.addNext()))
|
||||
propertyIt.push();
|
||||
}
|
||||
ok = propertyData.isValid();
|
||||
} else {
|
||||
while (!activeValue.isNull()
|
||||
&& deserializationError == QAbstractProtobufSerializer::NoError) {
|
||||
if (deserializeObject(&propertyIt.addNext()))
|
||||
propertyIt.push();
|
||||
}
|
||||
}
|
||||
ok = deserializationError == QAbstractProtobufSerializer::NoError;
|
||||
return propertyData;
|
||||
}
|
||||
|
||||
auto handler = QtProtobufPrivate::findHandler(metaType);
|
||||
if (handler.deserializer) {
|
||||
while (!activeValue.isNull()
|
||||
&& deserializationError == QAbstractProtobufSerializer::NoError) {
|
||||
handler
|
||||
.deserializer([this](QProtobufMessage
|
||||
*message) { return this->deserializeObject(message); },
|
||||
propertyData.data());
|
||||
}
|
||||
ok = propertyData.isValid();
|
||||
} else {
|
||||
int userType = propertyData.userType();
|
||||
auto handler = handlers.constFind(userType);
|
||||
|
|
|
|||
|
|
@ -189,6 +189,25 @@ void qRegisterProtobufTypes()
|
|||
registerFunc();
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QtProtobufPrivate::AbstractRepeatedIterator
|
||||
\internal
|
||||
*/
|
||||
|
||||
/*!
|
||||
\class template <typename T> class QtProtobufPrivate::ListIterator
|
||||
\internal
|
||||
*/
|
||||
|
||||
/*!
|
||||
\class template <typename K, typename V> class QtProtobufPrivate::MapIterator
|
||||
\internal
|
||||
*/
|
||||
|
||||
namespace QtProtobufPrivate {
|
||||
AbstractRepeatedIterator::~AbstractRepeatedIterator() = default;
|
||||
}
|
||||
|
||||
/*!
|
||||
\struct QtProtobufPrivate::SerializationHandler
|
||||
\internal
|
||||
|
|
@ -196,53 +215,4 @@ void qRegisterProtobufTypes()
|
|||
class serialization/deserialization.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename V, typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0> void QtProtobufPrivate::serializeList(
|
||||
const QAbstractProtobufSerializer *serializer, const QVariant &listValue,
|
||||
const QProtobufFieldInfo &fieldInfo)
|
||||
\internal
|
||||
\brief Default serializer template for list of type T objects that inherits
|
||||
from QProtobufMessage.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename K, typename V, typename std::enable_if_t<!std::is_base_of<QProtobufMessage, V>::value, int> = 0> void QtProtobufPrivate::serializeMap(
|
||||
const QAbstractProtobufSerializer *serializer, const QVariant &value,
|
||||
const QProtobufFieldInfo &fieldInfo)
|
||||
\internal
|
||||
\brief Default serializer template for map of key K, value V.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename K, typename V, typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0> void QtProtobufPrivate::serializeMap(
|
||||
const QAbstractProtobufSerializer *serializer, const QVariant &value,
|
||||
const QProtobufFieldInfo &fieldInfo)
|
||||
\internal
|
||||
\brief Default serializer template for map of type key K, value V.
|
||||
Specialization for V that inherits from QProtobufMessage.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename V, typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0> void QtProtobufPrivate::deserializeList(
|
||||
const QAbstractProtobufSerializer *serializer, QVariant &previous)
|
||||
\internal
|
||||
\brief Default deserializer template for list of type T objects that
|
||||
inherits from QProtobufMessage.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename K, typename V, typename std::enable_if_t<!std::is_base_of<QProtobufMessage, V>::value, int> = 0> void QtProtobufPrivate::deserializeMap(
|
||||
const QAbstractProtobufSerializer *serializer, QVariant &previous)
|
||||
\internal
|
||||
\brief Default deserializer template for map of key K, value V.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename K, typename V, typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0> void QtProtobufPrivate::deserializeMap(
|
||||
const QAbstractProtobufSerializer *serializer, QVariant &previous)
|
||||
\internal
|
||||
\brief Default deserializer template for map of type key K, value V.
|
||||
Specialization for V that inherits from QProtobufMessage.
|
||||
*/
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@
|
|||
|
||||
#include <QtProtobuf/qprotobufmessage.h>
|
||||
#include <QtProtobuf/qprotobufpropertyordering.h>
|
||||
#include <QtProtobuf/qprotobufrepeatediterator.h>
|
||||
#include <QtProtobuf/qtprotobuftypes.h>
|
||||
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qmetaobject.h>
|
||||
#include <QtCore/qmetatype.h>
|
||||
#include <QtCore/qxpfunctional.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
|
@ -31,93 +31,9 @@ struct ProtoTypeRegistrar
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
namespace QtProtobufPrivate {
|
||||
extern Q_PROTOBUF_EXPORT void registerOrdering(QMetaType type, QProtobufPropertyOrdering ordering);
|
||||
|
||||
using MessageFieldSerializer = qxp::function_ref<void(const QProtobufMessage *,
|
||||
const QProtobufFieldInfo &)>;
|
||||
using MessageFieldDeserializer = qxp::function_ref<bool(QProtobufMessage *)>;
|
||||
|
||||
using Serializer = void (*)(MessageFieldSerializer, const void *, const QProtobufFieldInfo &);
|
||||
using Deserializer = void (*)(MessageFieldDeserializer, void *);
|
||||
|
||||
struct SerializationHandler
|
||||
{
|
||||
Serializer serializer = nullptr; /*!< serializer assigned to class */
|
||||
Deserializer deserializer = nullptr; /*!< deserializer assigned to class */
|
||||
};
|
||||
|
||||
extern Q_PROTOBUF_EXPORT void registerHandler(QMetaType type, Serializer serializer,
|
||||
Deserializer deserializer);
|
||||
|
||||
inline void ensureValue(const void *valuePtr)
|
||||
{
|
||||
Q_ASSERT_X(valuePtr != nullptr, "QAbstractProtobufSerializer", "Value is nullptr");
|
||||
}
|
||||
|
||||
template <typename V,
|
||||
typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0>
|
||||
void serializeList(MessageFieldSerializer serializer, const void *valuePtr,
|
||||
const QProtobufFieldInfo &fieldInfo)
|
||||
{
|
||||
ensureValue(valuePtr);
|
||||
|
||||
for (const auto &value : *static_cast<const QList<V> *>(valuePtr))
|
||||
serializer(&value, fieldInfo);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void serializeMap(MessageFieldSerializer serializer, const void *valuePtr,
|
||||
const QProtobufFieldInfo &fieldInfo)
|
||||
{
|
||||
ensureValue(valuePtr);
|
||||
|
||||
using QProtobufMapEntry = QProtobufMapEntry<K, const V>;
|
||||
static_assert(!std::is_pointer_v<typename QProtobufMapEntry::KeyType>,
|
||||
"Map key must not be message");
|
||||
QProtobufMapEntry el;
|
||||
const auto *mapPtr = static_cast<const QHash<K, V> *>(valuePtr);
|
||||
for (const auto &[k, v] : mapPtr->asKeyValueRange()) {
|
||||
el.setKey(k);
|
||||
|
||||
if constexpr (std::is_pointer_v<typename QProtobufMapEntry::ValueType>)
|
||||
el.setValue(&v);
|
||||
else
|
||||
el.setValue(v);
|
||||
|
||||
serializer(&el, fieldInfo);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename V,
|
||||
typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0>
|
||||
void deserializeList(MessageFieldDeserializer deserializer, void *valuePtr)
|
||||
{
|
||||
ensureValue(valuePtr);
|
||||
|
||||
auto *listPtr = static_cast<QList<V> *>(valuePtr);
|
||||
if (V item; deserializer(&item))
|
||||
listPtr->append(std::move(item));
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void deserializeMap(MessageFieldDeserializer deserializer, void *valuePtr)
|
||||
{
|
||||
using QProtobufMapEntry = QProtobufMapEntry<K, V>;
|
||||
static_assert(!std::is_pointer_v<typename QProtobufMapEntry::KeyType>,
|
||||
"Map key must not be message");
|
||||
auto *mapPtr = static_cast<QHash<K, V> *>(valuePtr);
|
||||
if (QProtobufMapEntry el; deserializer(&el)) {
|
||||
auto it = mapPtr->emplace(std::move(el).key());
|
||||
|
||||
if constexpr (std::is_pointer_v<typename QProtobufMapEntry::ValueType>)
|
||||
*it = std::move(*el.value());
|
||||
else
|
||||
*it = std::move(el).value();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if_t<std::is_enum<T>::value, bool> = true>
|
||||
static std::optional<QList<T>> intToEnumList(QList<QtProtobuf::int64> v)
|
||||
{
|
||||
|
|
@ -165,6 +81,100 @@ static QStringList enumToStringList(QList<T> v)
|
|||
|
||||
return stringList;
|
||||
}
|
||||
|
||||
class Q_PROTOBUF_EXPORT AbstractRepeatedIterator
|
||||
{
|
||||
public:
|
||||
virtual ~AbstractRepeatedIterator() noexcept;
|
||||
|
||||
virtual bool hasNext() const noexcept = 0;
|
||||
virtual QProtobufMessage &next() const noexcept = 0;
|
||||
|
||||
virtual QProtobufMessage &addNext() noexcept = 0;
|
||||
virtual void push() noexcept = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ListIterator : public AbstractRepeatedIterator
|
||||
{
|
||||
public:
|
||||
~ListIterator() noexcept override = default;
|
||||
|
||||
bool hasNext() const noexcept override { return m_it != m_list->end(); }
|
||||
QProtobufMessage &next() const noexcept override
|
||||
{
|
||||
Q_ASSERT(m_it != m_list->end());
|
||||
return *m_it++;
|
||||
}
|
||||
|
||||
QProtobufMessage &addNext() noexcept override { return m_list->emplace_back(T()); }
|
||||
/* protobuf allows having elements in the repeated fields that are failed to deserialize */
|
||||
void push() noexcept override { }
|
||||
|
||||
static QProtobufRepeatedIterator fromList(QList<T> &list) noexcept
|
||||
{
|
||||
return QProtobufRepeatedIterator(new ListIterator<T>(list));
|
||||
}
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY_MOVE(ListIterator)
|
||||
|
||||
explicit ListIterator(QList<T> &list) : m_list(&list), m_it(m_list->begin()) { }
|
||||
QList<T> *m_list = nullptr;
|
||||
mutable typename QList<T>::Iterator m_it;
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
class MapIterator : public AbstractRepeatedIterator
|
||||
{
|
||||
using MapEntry = QProtobufMapEntry<K, V>;
|
||||
static_assert(!std::is_pointer_v<typename MapEntry::KeyType>, "Map key must not be message");
|
||||
|
||||
public:
|
||||
~MapIterator() noexcept override = default;
|
||||
|
||||
bool hasNext() const noexcept override { return m_it != m_hash->end(); }
|
||||
QProtobufMessage &next() const noexcept override
|
||||
{
|
||||
Q_ASSERT(m_it != m_hash->end());
|
||||
m_mapEntry.setKey(m_it.key());
|
||||
if constexpr (std::is_pointer_v<typename MapEntry::ValueType>)
|
||||
m_mapEntry.setValue(&m_it.value());
|
||||
else
|
||||
m_mapEntry.setValue(m_it.value());
|
||||
m_it++;
|
||||
return m_mapEntry;
|
||||
}
|
||||
|
||||
QProtobufMessage &addNext() noexcept override
|
||||
{
|
||||
m_mapEntry.setKey({});
|
||||
m_mapEntry.setValue({});
|
||||
return m_mapEntry;
|
||||
}
|
||||
void push() noexcept override
|
||||
{
|
||||
auto it = m_hash->emplace(m_mapEntry.key());
|
||||
if constexpr (std::is_pointer_v<typename MapEntry::ValueType>)
|
||||
*it = std::move(*m_mapEntry.value());
|
||||
else
|
||||
*it = std::move(m_mapEntry).value();
|
||||
}
|
||||
|
||||
static QProtobufRepeatedIterator fromHash(QHash<K, V> &hash) noexcept
|
||||
{
|
||||
return QProtobufRepeatedIterator(new MapIterator<K, V>(hash));
|
||||
}
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY_MOVE(MapIterator)
|
||||
|
||||
explicit MapIterator(QHash<K, V> &hash) : m_hash(&hash), m_it(m_hash->begin()) { }
|
||||
QHash<K, V> *m_hash = nullptr;
|
||||
mutable typename QHash<K, V>::Iterator m_it;
|
||||
mutable MapEntry m_mapEntry;
|
||||
};
|
||||
|
||||
} // namespace QtProtobufPrivate
|
||||
|
||||
Q_PROTOBUF_EXPORT void qRegisterProtobufTypes();
|
||||
|
|
@ -173,18 +183,16 @@ template<typename T>
|
|||
inline void qRegisterProtobufType()
|
||||
{
|
||||
T::registerTypes();
|
||||
QMetaType::registerMutableView<
|
||||
QList<T>, QProtobufRepeatedIterator>(&QtProtobufPrivate::ListIterator<T>::fromList);
|
||||
QtProtobufPrivate::registerOrdering(QMetaType::fromType<T>(), T::staticPropertyOrdering);
|
||||
QtProtobufPrivate::registerHandler(QMetaType::fromType<QList<T>>(),
|
||||
QtProtobufPrivate::serializeList<T>,
|
||||
QtProtobufPrivate::deserializeList<T>);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
inline void qRegisterProtobufMapType()
|
||||
{
|
||||
QtProtobufPrivate::registerHandler(QMetaType::fromType<QHash<K, V>>(),
|
||||
QtProtobufPrivate::serializeMap<K, V>,
|
||||
QtProtobufPrivate::deserializeMap<K, V>);
|
||||
QMetaType::registerMutableView<
|
||||
QHash<K, V>, QProtobufRepeatedIterator>(&QtProtobufPrivate::MapIterator<K, V>::fromHash);
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if_t<std::is_enum<T>::value, bool> = true>
|
||||
|
|
|
|||
|
|
@ -18,9 +18,33 @@
|
|||
#include <QtProtobuf/qprotobufregistration.h>
|
||||
#include <QtProtobuf/qtprotobufexports.h>
|
||||
|
||||
#include <QtCore/qxpfunctional.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtProtobufPrivate {
|
||||
|
||||
inline void ensureValue(const void *valuePtr)
|
||||
{
|
||||
Q_ASSERT_X(valuePtr != nullptr, "QAbstractProtobufSerializer", "Value is nullptr");
|
||||
}
|
||||
|
||||
using MessageFieldSerializer = qxp::function_ref<void(const QProtobufMessage *,
|
||||
const QProtobufFieldInfo &)>;
|
||||
using MessageFieldDeserializer = qxp::function_ref<bool(QProtobufMessage *)>;
|
||||
|
||||
using Serializer = void (*)(MessageFieldSerializer, const void *, const QProtobufFieldInfo &);
|
||||
using Deserializer = void (*)(MessageFieldDeserializer, void *);
|
||||
|
||||
struct SerializationHandler
|
||||
{
|
||||
Serializer serializer = nullptr; /*!< serializer assigned to class */
|
||||
Deserializer deserializer = nullptr; /*!< deserializer assigned to class */
|
||||
};
|
||||
|
||||
extern Q_PROTOBUF_EXPORT void registerHandler(QMetaType type, Serializer serializer,
|
||||
Deserializer deserializer);
|
||||
|
||||
extern Q_PROTOBUF_EXPORT SerializationHandler findHandler(QMetaType type);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include <QtProtobuf/qprotobufmessage.h>
|
||||
#include <QtProtobuf/qprotobufregistration.h>
|
||||
#include <QtProtobuf/qprotobufrepeatediterator.h>
|
||||
|
||||
/*!
|
||||
\class QProtobufRepeatedIterator
|
||||
\inmodule QtProtobuf
|
||||
\since 6.8
|
||||
|
||||
\brief Allows iterating over repeated protobuf types.
|
||||
|
||||
Allows iterating over repeated protobuf types and access the repeated field elements as
|
||||
reference to QProtobufMessage.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs iterator from \a data pointer.
|
||||
*/
|
||||
QProtobufRepeatedIterator::QProtobufRepeatedIterator(QtProtobufPrivate::AbstractRepeatedIterator
|
||||
*data) noexcept
|
||||
: m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys iterator.
|
||||
*/
|
||||
QProtobufRepeatedIterator::~QProtobufRepeatedIterator() noexcept
|
||||
{
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn QProtobufRepeatedIterator::QProtobufRepeatedIterator(QProtobufRepeatedIterator &&other) noexcept
|
||||
|
||||
Move-constructs a new QProtobufRepeatedIterator from \a other.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QProtobufRepeatedIterator &QProtobufRepeatedIterator::operator=(QProtobufRepeatedIterator &&other) noexcept
|
||||
|
||||
Move-assigns \a other to this QProtobufRepeatedIterator and returns a reference to
|
||||
the updated object.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn bool QProtobufRepeatedIterator::isValid() const noexcept
|
||||
|
||||
Returns \c true if the iterator points to a valid data object.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns \c true if the iterator can read the next element from the repeated field.
|
||||
*/
|
||||
bool QProtobufRepeatedIterator::hasNext() const noexcept
|
||||
{
|
||||
return m_data->hasNext();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the next element under from the repeated field.
|
||||
*/
|
||||
QProtobufMessage &QProtobufRepeatedIterator::next() const noexcept
|
||||
{
|
||||
return m_data->next();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the reference to the new temporary element in the repeated field.
|
||||
*/
|
||||
QProtobufMessage &QProtobufRepeatedIterator::addNext() noexcept
|
||||
{
|
||||
return m_data->addNext();
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds the element, created by addNext function, to the repeated field.
|
||||
*/
|
||||
void QProtobufRepeatedIterator::push() const noexcept
|
||||
{
|
||||
return m_data->push();
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#ifndef QPROTOBUFREPEATEDITERATOR_H
|
||||
#define QPROTOBUFREPEATEDITERATOR_H
|
||||
|
||||
#include <QtProtobuf/qtprotobufexports.h>
|
||||
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qlist.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QProtobufMessage;
|
||||
|
||||
namespace QtProtobufPrivate {
|
||||
class AbstractRepeatedIterator;
|
||||
}
|
||||
|
||||
class QProtobufRepeatedIterator
|
||||
{
|
||||
public:
|
||||
QProtobufRepeatedIterator() noexcept = default;
|
||||
Q_PROTOBUF_EXPORT explicit QProtobufRepeatedIterator(QtProtobufPrivate::AbstractRepeatedIterator
|
||||
*data) noexcept;
|
||||
Q_PROTOBUF_EXPORT ~QProtobufRepeatedIterator() noexcept;
|
||||
QProtobufRepeatedIterator(QProtobufRepeatedIterator &&other) noexcept
|
||||
: m_data(std::exchange(other.m_data, nullptr))
|
||||
{
|
||||
}
|
||||
QProtobufRepeatedIterator &operator=(QProtobufRepeatedIterator &&other) noexcept
|
||||
{
|
||||
std::swap(m_data, other.m_data);
|
||||
return *this;
|
||||
};
|
||||
|
||||
[[nodiscard]] bool isValid() const noexcept { return m_data != nullptr; }
|
||||
|
||||
[[nodiscard]] Q_PROTOBUF_EXPORT bool hasNext() const noexcept;
|
||||
[[nodiscard]] Q_PROTOBUF_EXPORT QProtobufMessage &next() const noexcept;
|
||||
|
||||
[[nodiscard]] Q_PROTOBUF_EXPORT QProtobufMessage &addNext() noexcept;
|
||||
Q_PROTOBUF_EXPORT void push() const noexcept;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QProtobufRepeatedIterator)
|
||||
|
||||
QtProtobufPrivate::AbstractRepeatedIterator *m_data = nullptr;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QPROTOBUFREPEATEDITERATOR_H
|
||||
|
|
@ -240,8 +240,7 @@ void QProtobufSerializerPrivate::clearError()
|
|||
|
||||
bool QProtobufSerializer::deserializeMessage(QProtobufMessage *message, QByteArrayView data) const
|
||||
{
|
||||
d_ptr->cachedPropertyValue = QVariant();
|
||||
d_ptr->cachedIndex = -1;
|
||||
d_ptr->clearCachedValue();
|
||||
d_ptr->clearError();
|
||||
d_ptr->it = QProtobufSelfcheckIterator::fromView(data);
|
||||
|
||||
|
|
@ -287,15 +286,16 @@ bool QProtobufSerializerPrivate::deserializeObject(QProtobufMessage *message)
|
|||
return false;
|
||||
}
|
||||
|
||||
auto prevCachedRepeatedIterator = std::move(cachedRepeatedIterator);
|
||||
auto restoreOnReturn = qScopeGuard([prevIt = it, prevCachedPropertyValue = cachedPropertyValue,
|
||||
prevCachedIndex = cachedIndex, this]() {
|
||||
prevCachedIndex = cachedIndex, &prevCachedRepeatedIterator,
|
||||
this]() {
|
||||
it = prevIt;
|
||||
cachedPropertyValue = prevCachedPropertyValue;
|
||||
cachedIndex = prevCachedIndex;
|
||||
cachedRepeatedIterator = std::move(prevCachedRepeatedIterator);
|
||||
});
|
||||
|
||||
cachedPropertyValue.clear();
|
||||
cachedIndex = -1;
|
||||
clearCachedValue();
|
||||
|
||||
QByteArrayView data = *array;
|
||||
clearError();
|
||||
|
|
@ -440,7 +440,7 @@ qsizetype QProtobufSerializerPrivate::skipSerializedFieldBytes(QProtobufSelfchec
|
|||
return std::distance(initialIt, QByteArray::const_iterator(it));
|
||||
}
|
||||
|
||||
void QProtobufSerializerPrivate::serializeProperty(const QVariant &propertyValue,
|
||||
void QProtobufSerializerPrivate::serializeProperty(QVariant propertyValue,
|
||||
const QProtobufFieldInfo &fieldInfo)
|
||||
{
|
||||
QMetaType metaType = propertyValue.metaType();
|
||||
|
|
@ -484,6 +484,13 @@ void QProtobufSerializerPrivate::serializeProperty(const QVariant &propertyValue
|
|||
return;
|
||||
}
|
||||
|
||||
if (propertyValue.canView(QMetaType::fromType<QProtobufRepeatedIterator>())) {
|
||||
QProtobufRepeatedIterator propertyIt = propertyValue.view<QProtobufRepeatedIterator>();
|
||||
while (propertyIt.hasNext())
|
||||
serializeObject(&propertyIt.next(), fieldInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
auto basicHandler = findIntegratedTypeHandler(metaType,
|
||||
fieldFlags
|
||||
.testFlag(QtProtobufPrivate::FieldFlag::NonPacked));
|
||||
|
|
@ -621,23 +628,33 @@ bool QProtobufSerializerPrivate::deserializeProperty(QProtobufMessage *message)
|
|||
setUnexpectedEndOfStreamError();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
auto handler = QtProtobufPrivate::findHandler(metaType);
|
||||
if (!handler.deserializer) {
|
||||
qProtoWarning() << "No deserializer for type" << metaType.name();
|
||||
QString error
|
||||
= QString::fromUtf8("No deserializer is registered for type %1")
|
||||
.arg(QString::fromUtf8(metaType.name()));
|
||||
setDeserializationError(
|
||||
QAbstractProtobufSerializer::NoDeserializerError,
|
||||
QCoreApplication::translate("QtProtobuf", error.toUtf8().data()));
|
||||
return false;
|
||||
}
|
||||
handler.deserializer([this](QProtobufMessage
|
||||
*message) { return this->deserializeObject(message); },
|
||||
cachedPropertyValue.data());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cachedPropertyValue.canView(QMetaType::fromType<QProtobufRepeatedIterator>())) {
|
||||
if (!cachedRepeatedIterator.isValid()) {
|
||||
cachedRepeatedIterator = cachedPropertyValue.view<QProtobufRepeatedIterator>();
|
||||
}
|
||||
if (deserializeObject(&cachedRepeatedIterator.addNext())) {
|
||||
cachedRepeatedIterator.push();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto handler = QtProtobufPrivate::findHandler(metaType);
|
||||
if (!handler.deserializer) {
|
||||
qProtoWarning() << "No deserializer for type" << metaType.name();
|
||||
QString error = QString::fromUtf8("No deserializer is registered for type %1")
|
||||
.arg(QString::fromUtf8(metaType.name()));
|
||||
setDeserializationError(QAbstractProtobufSerializer::NoDeserializerError,
|
||||
QCoreApplication::translate("QtProtobuf", error.toUtf8().data()));
|
||||
return false;
|
||||
}
|
||||
handler.deserializer([this](QProtobufMessage
|
||||
*message) { return this->deserializeObject(message); },
|
||||
cachedPropertyValue.data());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -649,12 +666,19 @@ bool QProtobufSerializerPrivate::storeCachedValue(QProtobufMessage *message)
|
|||
QProtobufFieldInfo fieldInfo(*ordering, cachedIndex);
|
||||
ok = QtProtobufSerializerHelpers::setMessageProperty(message, fieldInfo,
|
||||
cachedPropertyValue);
|
||||
cachedPropertyValue.clear();
|
||||
cachedIndex = -1;
|
||||
|
||||
clearCachedValue();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void QProtobufSerializerPrivate::clearCachedValue()
|
||||
{
|
||||
cachedPropertyValue.clear();
|
||||
cachedIndex = -1;
|
||||
cachedRepeatedIterator = QProtobufRepeatedIterator();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the last deserialization error for the serializer instance.
|
||||
\sa deserializationErrorString()
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <QtProtobuf/qabstractprotobufserializer.h>
|
||||
#include <QtProtobuf/qprotobufserializer.h>
|
||||
#include <QtProtobuf/qprotobufrepeatediterator.h>
|
||||
#include <QtProtobuf/qtprotobuftypes.h>
|
||||
|
||||
#include <QtProtobuf/private/qprotobufselfcheckiterator_p.h>
|
||||
|
|
@ -511,7 +512,7 @@ public:
|
|||
|
||||
void serializeMessage(const QProtobufMessage *message);
|
||||
|
||||
void serializeProperty(const QVariant &propertyValue,
|
||||
void serializeProperty(QVariant propertyValue,
|
||||
const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo);
|
||||
[[nodiscard]] bool deserializeProperty(QProtobufMessage *message);
|
||||
|
||||
|
|
@ -521,6 +522,7 @@ public:
|
|||
void setUnexpectedEndOfStreamError();
|
||||
|
||||
[[nodiscard]] bool storeCachedValue(QProtobufMessage *message);
|
||||
void clearCachedValue();
|
||||
|
||||
QAbstractProtobufSerializer::DeserializationError deserializationError =
|
||||
QAbstractProtobufSerializer::NoDeserializerError;
|
||||
|
|
@ -534,6 +536,7 @@ public:
|
|||
static const QtProtobufPrivate::QProtobufFieldInfo mapValueOrdering;
|
||||
|
||||
QVariant cachedPropertyValue;
|
||||
QProtobufRepeatedIterator cachedRepeatedIterator;
|
||||
int cachedIndex = -1;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -17,9 +17,10 @@
|
|||
|
||||
#include <QtProtobufQtCoreTypes/qtprotobufqtcoretypesexports.h>
|
||||
|
||||
#include <QtProtobuf/qtprotobuftypes.h>
|
||||
#include <QtProtobuf/qprotobufregistration.h>
|
||||
#include <QtProtobuf/private/qprotobufregistration_p.h>
|
||||
#include <QtProtobuf/qabstractprotobufserializer.h>
|
||||
#include <QtProtobuf/qprotobufregistration.h>
|
||||
#include <QtProtobuf/qtprotobuftypes.h>
|
||||
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtCore/private/qglobal_p.h>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <QtProtobufWellKnownTypes/qtprotobufwellknowntypesglobal.h>
|
||||
|
||||
#include <QtProtobuf/private/qprotobufmessage_p.h>
|
||||
#include <QtProtobuf/private/qprotobufregistration_p.h>
|
||||
#include <QtProtobuf/private/qprotobufserializer_p.h>
|
||||
#include <QtProtobuf/qabstractprotobufserializer.h>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue