Remove QAbstractProtobufSerializer::(de)serializeObject interface

Replace the interface methods with the qxp::function_ref with the
respective arguments. This will break the dependency between the
protobuf message registry and the QAbstractProtobufSerializer.

Now the registry is standalone unit with own rules that can be used
or not used by the serializers. If serializers want to use the
registry, they now need to supply it with the respective
(de)serializers for the message fields of the protobuf message type.

QAbstractProtobufSerializer implementations meanwhile only need to
know how to (de)serialize the whole messages but not fields. This
was the last chunk of the interface cleaning.

Adjust the implementation of the existing serializers respectively.

Pick-to: 6.8
Task-number: QTBUG-123626
Change-Id: I772a330e8f9757d998f0e7ea138d12bbfce020b8
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Alexey Edelev 2024-08-21 19:09:52 +02:00
parent acac560fb1
commit 8ec55cb0cf
10 changed files with 129 additions and 175 deletions

View File

@ -37,11 +37,6 @@ public:
virtual DeserializationError deserializationError() const = 0;
virtual QString deserializationErrorString() const = 0;
virtual void
serializeObject(const QProtobufMessage *message,
const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo) const = 0;
virtual bool deserializeObject(QProtobufMessage *message) const = 0;
protected:
virtual QByteArray serializeMessage(const QProtobufMessage *message) const = 0;
virtual bool deserializeMessage(QProtobufMessage *message, QByteArrayView data) const = 0;

View File

@ -187,8 +187,7 @@ public:
return QJsonValue(arr);
}
QProtobufJsonSerializerPrivate(QProtobufJsonSerializer *q)
: qPtr(q)
QProtobufJsonSerializerPrivate()
{
[[maybe_unused]] static bool initialized = []() -> bool {
handlers[qMetaTypeId<QtProtobuf::int32>()] = createCommonHandler<QtProtobuf::int32>();
@ -275,7 +274,7 @@ public:
auto store = activeValue.toObject();
activeValue = QJsonObject();
auto *messageProperty = propertyValue.value<QProtobufMessage *>();
serializeObject(messageProperty);
serializeObjectImpl(messageProperty);
store.insert(fieldInfo.jsonName().toString(), activeValue);
activeValue = store;
return;
@ -302,6 +301,11 @@ 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
@ -309,12 +313,12 @@ public:
const auto fieldName = fieldInfo.jsonName().toString();
QJsonObject activeObject = activeValue.toObject();
activeValue = activeObject.value(fieldName).toArray();
handler.serializer(qPtr, propertyValue.constData(), fieldInfo);
handler.serializer(serializerFunction, propertyValue.constData(), fieldInfo);
if (!activeValue.toArray().empty())
activeObject.insert(fieldName, activeValue);
activeValue = activeObject;
} else {
handler.serializer(qPtr, propertyValue.constData(), fieldInfo);
handler.serializer(serializerFunction, propertyValue.constData(), fieldInfo);
}
} else {
QJsonObject activeObject = activeValue.toObject();
@ -333,24 +337,8 @@ public:
}
}
void serializeObject(const QProtobufMessage *message)
{
// if a message is not initialized, just return empty { }
if (message) {
auto ordering = message->propertyOrdering();
Q_ASSERT(ordering != nullptr);
for (int index = 0; index < ordering->fieldCount(); ++index) {
int fieldIndex = ordering->fieldNumber(index);
Q_ASSERT_X(fieldIndex <= ProtobufFieldNumMax && fieldIndex >= ProtobufFieldNumMin,
"",
"fieldIndex is out of range");
QProtobufFieldInfo fieldInfo(*ordering, index);
QVariant propertyValue = QtProtobufSerializerHelpers::messageProperty(message,
fieldInfo);
serializeProperty(propertyValue, fieldInfo);
}
}
}
void serializeObject(const QProtobufMessage *message, const QProtobufFieldInfo &fieldInfo);
void serializeObjectImpl(const QProtobufMessage *message);
template <typename T>
static QVariant deserializeCommon(const QJsonValue &value, bool &ok)
@ -533,6 +521,9 @@ public:
auto handler = QtProtobufPrivate::findHandler(metaType);
if (handler.deserializer) {
auto deserializerFunction = [this](QProtobufMessage *message) {
return this->deserializeObject(message);
};
if (activeValue.isArray()) {
QJsonArray array = activeValue.toArray();
if (array.isEmpty()) {
@ -540,15 +531,14 @@ public:
activeValue = {};
return propertyData;
}
if (!array.at(0).isObject()) { // Enum array
handler.deserializer(qPtr, propertyData.data());
handler.deserializer(deserializerFunction, propertyData.data());
ok = propertyData.isValid();
} else {
while (!array.isEmpty() &&
deserializationError == QAbstractProtobufSerializer::NoError) {
activeValue = array.takeAt(0);
handler.deserializer(qPtr, propertyData.data());
handler.deserializer(deserializerFunction, propertyData.data());
}
ok = propertyData.isValid();
}
@ -557,7 +547,7 @@ public:
// This is required to deserialize the map fields.
while (!activeValue.isNull()
&& deserializationError == QAbstractProtobufSerializer::NoError) {
handler.deserializer(qPtr, propertyData.data());
handler.deserializer(deserializerFunction, propertyData.data());
}
ok = propertyData.isValid();
}
@ -715,9 +705,6 @@ public:
QVariant cachedPropertyValue;
int cachedIndex = -1;
private:
QProtobufJsonSerializer *qPtr;
};
bool QProtobufJsonSerializerPrivate::storeCachedValue(QProtobufMessage *message)
@ -736,14 +723,31 @@ bool QProtobufJsonSerializerPrivate::storeCachedValue(QProtobufMessage *message)
QProtobufJsonSerializerPrivate::SerializerRegistry QProtobufJsonSerializerPrivate::handlers = {};
void QProtobufJsonSerializerPrivate::serializeObjectImpl(const QProtobufMessage *message)
{
// if a message is not initialized, just return empty { }
if (message) {
auto ordering = message->propertyOrdering();
Q_ASSERT(ordering != nullptr);
for (int index = 0; index < ordering->fieldCount(); ++index) {
int fieldIndex = ordering->fieldNumber(index);
Q_ASSERT_X(fieldIndex <= ProtobufFieldNumMax && fieldIndex >= ProtobufFieldNumMin, "",
"fieldIndex is out of range");
QProtobufFieldInfo fieldInfo(*ordering, index);
QVariant propertyValue = QtProtobufSerializerHelpers::messageProperty(message,
fieldInfo);
serializeProperty(propertyValue, fieldInfo);
}
}
}
void QProtobufJsonSerializerPrivate::clearError()
{
deserializationError = QAbstractProtobufSerializer::NoError;
deserializationErrorString.clear();
}
QProtobufJsonSerializer::QProtobufJsonSerializer() :
d_ptr(new QProtobufJsonSerializerPrivate(this))
QProtobufJsonSerializer::QProtobufJsonSerializer() : d_ptr(new QProtobufJsonSerializerPrivate)
{
}
@ -772,7 +776,7 @@ QByteArray QProtobufJsonSerializer::serializeMessage(const QProtobufMessage *mes
{
d_ptr->clearError();
d_ptr->activeValue = QJsonObject();
d_ptr->serializeObject(message);
d_ptr->serializeObjectImpl(message);
QJsonDocument doc;
doc.setObject(d_ptr->activeValue.toObject());
d_ptr->activeValue = QJsonObject();
@ -801,36 +805,31 @@ bool QProtobufJsonSerializer::deserializeMessage(QProtobufMessage *message,
return d_ptr->deserializeObject(message);
}
void QProtobufJsonSerializer::serializeObject(const QProtobufMessage *message,
const QProtobufFieldInfo &fieldInfo) const
void QProtobufJsonSerializerPrivate::serializeObject(const QProtobufMessage *message,
const QProtobufFieldInfo &fieldInfo)
{
if (d_ptr->activeValue.isArray()) {
auto store = d_ptr->activeValue.toArray();
d_ptr->activeValue = QJsonObject();
d_ptr->serializeObject(message);
store.append(d_ptr->activeValue);
d_ptr->activeValue = store;
if (activeValue.isArray()) {
auto store = activeValue.toArray();
activeValue = QJsonObject();
serializeObjectImpl(message);
store.append(activeValue);
activeValue = store;
} else {
auto store = d_ptr->activeValue.toObject();
auto store = activeValue.toObject();
const QString fieldName = fieldInfo.jsonName().toString();
d_ptr->activeValue = QJsonObject();
activeValue = QJsonObject();
if (fieldInfo.fieldFlags() & QtProtobufPrivate::FieldFlag::Map) {
QJsonObject mapObject = store.value(fieldName).toObject();
d_ptr->serializeObject(message);
serializeObjectImpl(message);
mapObject.insert(message->property("key").toString(),
d_ptr->activeValue.toObject().value("value"_L1));
activeValue.toObject().value("value"_L1));
store.insert(fieldName, mapObject);
} else {
d_ptr->serializeObject(message);
store.insert(fieldName, d_ptr->activeValue);
serializeObjectImpl(message);
store.insert(fieldName, activeValue);
}
d_ptr->activeValue = store;
activeValue = store;
}
}
bool QProtobufJsonSerializer::deserializeObject(QProtobufMessage *message) const
{
return d_ptr->deserializeObject(message);
}
QT_END_NAMESPACE

View File

@ -25,15 +25,10 @@ public:
DeserializationError deserializationError() const override;
QString deserializationErrorString() const override;
private:
protected:
QByteArray serializeMessage(const QProtobufMessage *message) const override;
bool deserializeMessage(QProtobufMessage *message, QByteArrayView data) const override;
void serializeObject(const QProtobufMessage *message,
const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo)
const override;
bool deserializeObject(QProtobufMessage *message) const override;
private:
std::unique_ptr<QProtobufJsonSerializerPrivate> d_ptr;
};

View File

@ -11,14 +11,14 @@
#include <QtProtobuf/qtprotobufglobal.h>
#include <QtProtobuf/qabstractprotobufserializer.h>
#include <QtProtobuf/qprotobufmessage.h>
#include <QtProtobuf/qprotobufpropertyordering.h>
#include <QtProtobuf/qtprotobuftypes.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qhash.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qxpfunctional.h>
QT_BEGIN_NAMESPACE
@ -35,9 +35,12 @@ struct ProtoTypeRegistrar
namespace QtProtobufPrivate {
extern Q_PROTOBUF_EXPORT void registerOrdering(QMetaType type, QProtobufPropertyOrdering ordering);
using Serializer = void (*)(const QAbstractProtobufSerializer *, const void *,
const QProtobufFieldInfo &);
using Deserializer = void (*)(const QAbstractProtobufSerializer *, void *);
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
{
@ -48,11 +51,6 @@ struct SerializationHandler
extern Q_PROTOBUF_EXPORT void registerHandler(QMetaType type, Serializer serializer,
Deserializer deserializer);
inline void ensureSerializer(const QAbstractProtobufSerializer *serializer)
{
Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "Serializer is null");
}
inline void ensureValue(const void *valuePtr)
{
Q_ASSERT_X(valuePtr != nullptr, "QAbstractProtobufSerializer", "Value is nullptr");
@ -60,21 +58,19 @@ inline void ensureValue(const void *valuePtr)
template <typename V,
typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0>
void serializeList(const QAbstractProtobufSerializer *serializer, const void *valuePtr,
void serializeList(MessageFieldSerializer serializer, const void *valuePtr,
const QProtobufFieldInfo &fieldInfo)
{
ensureSerializer(serializer);
ensureValue(valuePtr);
for (const auto &value : *static_cast<const QList<V> *>(valuePtr))
serializer->serializeObject(&value, fieldInfo);
serializer(&value, fieldInfo);
}
template <typename K, typename V>
void serializeMap(const QAbstractProtobufSerializer *serializer, const void *valuePtr,
void serializeMap(MessageFieldSerializer serializer, const void *valuePtr,
const QProtobufFieldInfo &fieldInfo)
{
ensureSerializer(serializer);
ensureValue(valuePtr);
using QProtobufMapEntry = QProtobufMapEntry<K, const V>;
@ -90,32 +86,29 @@ void serializeMap(const QAbstractProtobufSerializer *serializer, const void *val
else
el.setValue(v);
serializer->serializeObject(&el, fieldInfo);
serializer(&el, fieldInfo);
}
}
template <typename V,
typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0>
void deserializeList(const QAbstractProtobufSerializer *serializer, void *valuePtr)
void deserializeList(MessageFieldDeserializer deserializer, void *valuePtr)
{
ensureSerializer(serializer);
ensureValue(valuePtr);
auto *listPtr = static_cast<QList<V> *>(valuePtr);
if (V item; serializer->deserializeObject(&item))
if (V item; deserializer(&item))
listPtr->append(std::move(item));
}
template <typename K, typename V>
void deserializeMap(const QAbstractProtobufSerializer *serializer, void *valuePtr)
void deserializeMap(MessageFieldDeserializer deserializer, void *valuePtr)
{
ensureSerializer(serializer);
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; serializer->deserializeObject(&el)) {
if (QProtobufMapEntry el; deserializer(&el)) {
auto it = mapPtr->emplace(std::move(el).key());
if constexpr (std::is_pointer_v<typename QProtobufMapEntry::ValueType>)

View File

@ -185,7 +185,7 @@ findIntegratedTypeHandler(QMetaType metaType, bool nonPacked)
/*!
Constructs a new serializer instance.
*/
QProtobufSerializer::QProtobufSerializer() : d_ptr(new QProtobufSerializerPrivate(this))
QProtobufSerializer::QProtobufSerializer() : d_ptr(new QProtobufSerializerPrivate)
{
}
@ -316,17 +316,6 @@ bool QProtobufSerializerPrivate::deserializeObject(QProtobufMessage *message)
return it.isValid();
}
void QProtobufSerializer::serializeObject(const QProtobufMessage *message,
const QProtobufFieldInfo &fieldInfo) const
{
d_ptr->serializeObject(message, fieldInfo);
}
bool QProtobufSerializer::deserializeObject(QProtobufMessage *message) const
{
return d_ptr->deserializeObject(message);
}
void QProtobufSerializerPrivate::serializeEnumList(const QList<QtProtobuf::int64> &value,
const QProtobufFieldInfo &fieldInfo)
{
@ -356,10 +345,6 @@ bool QProtobufSerializerPrivate::deserializeEnumList(QList<QtProtobuf::int64> &v
return true;
}
QProtobufSerializerPrivate::QProtobufSerializerPrivate(QProtobufSerializer *q) : q_ptr(q)
{
}
/*!
\internal
Encode a property field index and its type into output bytes.
@ -519,7 +504,11 @@ void QProtobufSerializerPrivate::serializeProperty(const QVariant &propertyValue
qProtoWarning() << "No serializer for type" << propertyValue.typeName();
return;
}
handler.serializer(q_ptr, propertyValue.constData(), fieldInfo);
handler.serializer([this](const QProtobufMessage *message,
const QProtobufFieldInfo
&fieldInfo) { this->serializeObject(message, fieldInfo); },
propertyValue.constData(), fieldInfo);
}
bool QProtobufSerializerPrivate::deserializeProperty(QProtobufMessage *message)
@ -644,7 +633,9 @@ bool QProtobufSerializerPrivate::deserializeProperty(QProtobufMessage *message)
QCoreApplication::translate("QtProtobuf", error.toUtf8().data()));
return false;
}
handler.deserializer(q_ptr, cachedPropertyValue.data());
handler.deserializer([this](QProtobufMessage
*message) { return this->deserializeObject(message); },
cachedPropertyValue.data());
}
return true;

View File

@ -27,15 +27,11 @@ public:
QString deserializationErrorString() const override;
void shouldPreserveUnknownFields(bool preserveUnknownFields);
private:
protected:
QByteArray serializeMessage(const QProtobufMessage *message) const override;
bool deserializeMessage(QProtobufMessage *message, QByteArrayView data) const override;
void serializeObject(const QProtobufMessage *message,
const QtProtobufPrivate::QProtobufFieldInfo &fieldInfo)
const override;
bool deserializeObject(QProtobufMessage *message) const override;
private:
std::unique_ptr<QProtobufSerializerPrivate> d_ptr;
};

View File

@ -154,7 +154,7 @@ public:
return !value.value<V>().isEmpty();
}
explicit QProtobufSerializerPrivate(QProtobufSerializer *q);
QProtobufSerializerPrivate() = default;
~QProtobufSerializerPrivate() = default;
// ###########################################################################
// Serializers
@ -538,7 +538,6 @@ public:
private:
Q_DISABLE_COPY_MOVE(QProtobufSerializerPrivate)
QProtobufSerializer *q_ptr;
};
inline bool

View File

@ -40,46 +40,44 @@ constexpr inline bool is_optional_v<std::optional<T>> = true;
template<typename QType, typename PType>
void registerQtTypeHandler()
{
registerHandler(QMetaType::fromType<QType>(),
[](const QAbstractProtobufSerializer *serializer, const void *valuePtr,
const QProtobufFieldInfo &info) {
QtProtobufPrivate::ensureSerializer(serializer);
QtProtobufPrivate::ensureValue(valuePtr);
registerHandler(
QMetaType::fromType<QType>(),
[](QtProtobufPrivate::MessageFieldSerializer serializer, const void *valuePtr,
const QProtobufFieldInfo &info) {
QtProtobufPrivate::ensureValue(valuePtr);
auto do_convert = [](const QType *qtype) {
auto res = convert(*qtype);
if constexpr (is_optional_v<decltype(res)>) {
return res;
} else {
return std::optional<PType>(std::move(res));
}
};
auto do_convert = [](const QType *qtype) {
auto res = convert(*qtype);
if constexpr (is_optional_v<decltype(res)>) {
return res;
} else {
return std::optional<PType>(std::move(res));
}
};
std::optional<PType> object =
do_convert(static_cast<const QType *>(valuePtr));
if (object) {
serializer->serializeObject(&(object.value()), info);
} else {
warnTypeConversionError();
}
},
[](const QAbstractProtobufSerializer *serializer, void *valuePtr) {
QtProtobufPrivate::ensureSerializer(serializer);
QtProtobufPrivate::ensureValue(valuePtr);
std::optional<PType> object = do_convert(static_cast<const QType *>(valuePtr));
if (object) {
serializer(&(object.value()), info);
} else {
warnTypeConversionError();
}
},
[](QtProtobufPrivate::MessageFieldDeserializer deserializer, void *valuePtr) {
QtProtobufPrivate::ensureValue(valuePtr);
PType object;
serializer->deserializeObject(&object);
auto res = convert(object);
auto *qtypePtr = static_cast<QType *>(valuePtr);
if constexpr (is_optional_v<decltype(res)>) {
if (!res)
warnTypeConversionError();
else
*qtypePtr = std::move(*res);
} else {
*qtypePtr = std::move(res);
}
});
PType object;
deserializer(&object);
auto res = convert(object);
auto *qtypePtr = static_cast<QType *>(valuePtr);
if constexpr (is_optional_v<decltype(res)>) {
if (!res)
warnTypeConversionError();
else
*qtypePtr = std::move(*res);
} else {
*qtypePtr = std::move(res);
}
});
}
} // namespace QtProtobufPrivate

View File

@ -35,11 +35,9 @@ AnyPrivate::AnyPrivate(const QMetaObject *metaObject,
{
}
static void serializerProxy(const QAbstractProtobufSerializer *serializer, const void *object,
const QProtobufFieldInfo &fieldInfo)
static void serializerProxy(QtProtobufPrivate::MessageFieldSerializer serializer,
const void *object, const QProtobufFieldInfo &fieldInfo)
{
QtProtobufPrivate::ensureSerializer(serializer);
if (object == nullptr)
return;
@ -50,14 +48,12 @@ static void serializerProxy(const QAbstractProtobufSerializer *serializer, const
google::protobuf::Any realAny;
realAny.setValue(any.value());
realAny.setTypeUrl(any.typeUrl());
serializer->serializeObject(&realAny, fieldInfo);
serializer(&realAny, fieldInfo);
}
static void listSerializerProxy(const QAbstractProtobufSerializer *serializer, const void *object,
const QProtobufFieldInfo &fieldInfo)
static void listSerializerProxy(QtProtobufPrivate::MessageFieldSerializer serializer,
const void *object, const QProtobufFieldInfo &fieldInfo)
{
QtProtobufPrivate::ensureSerializer(serializer);
if (object == nullptr)
return;
@ -66,20 +62,19 @@ static void listSerializerProxy(const QAbstractProtobufSerializer *serializer, c
google::protobuf::Any realAny;
realAny.setValue(any.value());
realAny.setTypeUrl(any.typeUrl());
serializer->serializeObject(&realAny, fieldInfo);
serializer(&realAny, fieldInfo);
}
}
static void listDeserializerProxy(const QAbstractProtobufSerializer *deserializer, void *object)
static void listDeserializerProxy(QtProtobufPrivate::MessageFieldDeserializer deserializer,
void *object)
{
QtProtobufPrivate::ensureSerializer(deserializer);
if (object == nullptr)
return;
auto &anyList = *static_cast<QList<Any> *>(object);
google::protobuf::Any realAny;
if (deserializer->deserializeObject(&realAny)) {
if (deserializer(&realAny)) {
Any any;
any.setTypeUrl(realAny.typeUrl());
any.setValue(realAny.value());
@ -89,15 +84,14 @@ static void listDeserializerProxy(const QAbstractProtobufSerializer *deserialize
}
}
static void deserializerProxy(const QAbstractProtobufSerializer *deserializer, void *object)
static void deserializerProxy(QtProtobufPrivate::MessageFieldDeserializer deserializer,
void *object)
{
QtProtobufPrivate::ensureSerializer(deserializer);
if (object == nullptr)
return;
google::protobuf::Any realAny;
if (deserializer->deserializeObject(&realAny)) {
if (deserializer(&realAny)) {
auto &any = *static_cast<Any *>(object);
any.setTypeUrl(realAny.typeUrl());
any.setValue(realAny.value());

View File

@ -39,12 +39,6 @@ protected:
{
return true;
}
void serializeObject(const QProtobufMessage *,
const QtProtobufPrivate::QProtobufFieldInfo &) const override
{
}
bool deserializeObject(QProtobufMessage *) const override { return true; }
};
} // namespace