1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QPROTOBUFSERIALIZER_H
6#define QPROTOBUFSERIALIZER_H
7
8#include <QtProtobuf/qtprotobufglobal.h>
9
10#include <QtProtobuf/qabstractprotobufserializer.h>
11
12#include <QtProtobuf/qtprotobuftypes.h>
13
14#include <QtProtobuf/QProtobufMessage>
15#include <QtCore/QVariant>
16#include <QtCore/QMetaObject>
17
18#include <functional>
19#include <memory>
20
21QT_BEGIN_NAMESPACE
22
23namespace QtProtobufPrivate {
24class QProtobufSelfcheckIterator;
25} // namespace QtProtobufPrivate
26
27class QProtobufSerializerPrivate;
28class Q_PROTOBUF_EXPORT QProtobufSerializer : public QAbstractProtobufSerializer
29{
30 Q_DISABLE_COPY_MOVE(QProtobufSerializer)
31public:
32 QProtobufSerializer();
33 ~QProtobufSerializer() override;
34
35 QProtobufSerializer::DeserializationError deserializationError() const override;
36 QString deserializationErrorString() const override;
37
38 QByteArray
39 serializeMessage(const QProtobufMessage *message,
40 const QtProtobufPrivate::QProtobufPropertyOrdering &ordering) const override;
41 bool deserializeMessage(QProtobufMessage *message,
42 const QtProtobufPrivate::QProtobufPropertyOrdering &ordering,
43 QByteArrayView data) const override;
44
45 QByteArray
46 serializeObject(const QProtobufMessage *message,
47 const QtProtobufPrivate::QProtobufPropertyOrdering &ordering,
48 const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const;
49 bool deserializeObject(QProtobufMessage *message,
50 const QtProtobufPrivate::QProtobufPropertyOrdering &ordering,
51 QtProtobufPrivate::QProtobufSelfcheckIterator &it) const;
52
53 QByteArray
54 serializeListObject(const QProtobufMessage *message,
55 const QtProtobufPrivate::QProtobufPropertyOrdering &ordering,
56 const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const;
57 bool deserializeListObject(QProtobufMessage *message,
58 const QtProtobufPrivate::QProtobufPropertyOrdering &ordering,
59 QtProtobufPrivate::QProtobufSelfcheckIterator &it) const;
60
61 QByteArray
62 serializeMapPair(const QVariant &key, const QVariant &value,
63 const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const;
64 bool deserializeMapPair(QVariant &key, QVariant &value,
65 QtProtobufPrivate::QProtobufSelfcheckIterator &it) const;
66
67 QByteArray
68 serializeEnum(QtProtobuf::int64 value,
69 const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const;
70 QByteArray
71 serializeEnumList(const QList<QtProtobuf::int64> &value,
72 const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const;
73
74 Q_REQUIRED_RESULT
75 bool deserializeEnum(QtProtobuf::int64 &value,
76 QtProtobufPrivate::QProtobufSelfcheckIterator &it) const;
77 Q_REQUIRED_RESULT
78 bool deserializeEnumList(QList<QtProtobuf::int64> &value,
79 QtProtobufPrivate::QProtobufSelfcheckIterator &it) const;
80
81private:
82 std::unique_ptr<QProtobufSerializerPrivate> d_ptr;
83};
84
85namespace QtProtobufPrivate {
86
87using Serializer = void (*)(const QProtobufSerializer *, const QVariant &,
88 const QProtobufPropertyOrderingInfo &, QByteArray &);
89using Deserializer = void (*)(const QProtobufSerializer *, QProtobufSelfcheckIterator &,
90 QVariant &);
91
92/*!
93 \private
94 \brief SerializationHandlers contains set of objects that required for class
95 serialization/deserialization
96 */
97struct SerializationHandler
98{
99 Serializer serializer = nullptr; /*!< serializer assigned to class */
100 Deserializer deserializer = nullptr; /*!< deserializer assigned to class */
101};
102
103extern Q_PROTOBUF_EXPORT SerializationHandler findHandler(QMetaType type);
104extern Q_PROTOBUF_EXPORT void registerHandler(QMetaType type, const SerializationHandler &handlers);
105
106/*!
107 \private
108 \brief default serializer template for type T that inherits from QProtobufMessage
109 */
110template<typename T,
111 typename std::enable_if_t<std::is_base_of<QProtobufMessage, T>::value, int> = 0>
112void serializeObject(const QProtobufSerializer *serializer, const QVariant &value,
113 const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer)
114{
115 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
116 buffer.append(serializer->serializeObject(message: value.value<T *>(), ordering: T::propertyOrdering, fieldInfo));
117}
118
119/*!
120 \private
121 \brief default serializer template for list of type T objects that inherits from QProtobufMessage
122 */
123template<typename V,
124 typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0>
125void serializeList(const QProtobufSerializer *serializer, const QVariant &listValue,
126 const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer)
127{
128 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
129 for (const auto &value : listValue.value<QList<V>>()) {
130 buffer.append(serializer->serializeListObject(message: &value, ordering: V::propertyOrdering, fieldInfo));
131 }
132}
133
134/*!
135 \private
136 \brief default serializer template for map of key K, value V
137 */
138template<typename K, typename V,
139 typename std::enable_if_t<!std::is_base_of<QProtobufMessage, V>::value, int> = 0>
140void serializeMap(const QProtobufSerializer *serializer, const QVariant &value,
141 const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer)
142{
143 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
144 for (const auto &[k, v] : value.value<QHash<K, V>>().asKeyValueRange()) {
145 buffer.append(serializer->serializeMapPair(key: QVariant::fromValue<K>(k),
146 value: QVariant::fromValue<V>(v), fieldInfo));
147 }
148}
149
150/*!
151 \private
152 \brief default serializer template for map of type key K, value V. Specialization for V that
153 inherits from QProtobufMessage
154 */
155template<typename K, typename V,
156 typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0>
157void serializeMap(const QProtobufSerializer *serializer, const QVariant &value,
158 const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer)
159{
160 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
161 for (const auto &[k, v] : value.value<QHash<K, V>>().asKeyValueRange()) {
162 buffer.append(serializer->serializeMapPair(key: QVariant::fromValue<K>(k),
163 value: QVariant::fromValue<V *>(&v), fieldInfo));
164 }
165}
166
167/*!
168 \private
169 \brief default serializer template for enum types
170 */
171template<typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
172void serializeEnum(const QProtobufSerializer *serializer, const QVariant &value,
173 const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer)
174{
175 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
176 buffer.append(a: serializer->serializeEnum(value: QtProtobuf::int64(value.value<T>()), fieldInfo));
177}
178
179/*!
180 \private
181 \brief default serializer template for enum list types
182 */
183template<typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
184void serializeEnumList(const QProtobufSerializer *serializer, const QVariant &value,
185 const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer)
186{
187 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
188 QList<QtProtobuf::int64> intList;
189 for (auto enumValue : value.value<QList<T>>()) {
190 intList.append(t: QtProtobuf::int64(enumValue));
191 }
192 buffer.append(a: serializer->serializeEnumList(value: intList, fieldInfo));
193}
194
195/*!
196 \private
197 \brief default deserializer template for type T that inherits from QProtobufMessage
198 */
199template<typename T,
200 typename std::enable_if_t<std::is_base_of<QProtobufMessage, T>::value, int> = 0>
201void deserializeObject(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it,
202 QVariant &to)
203{
204 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
205 Q_ASSERT_X(to.isNull() || to.metaType() == QMetaType::fromType<T *>(), "QProtobufSerializer",
206 "Property should be either uninitialized or contain a valid pointer");
207
208 T *value = to.value<T *>();
209 if (value == nullptr) {
210 value = new T;
211 to = QVariant::fromValue<T *>(value);
212 }
213 serializer->deserializeObject(message: value, ordering: T::propertyOrdering, it);
214}
215
216/*!
217 \private
218 \brief default deserializer template for list of type T objects that inherits from QProtobufMessage
219 */
220template<typename V,
221 typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0>
222void deserializeList(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it,
223 QVariant &previous)
224{
225 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
226
227 V newValue;
228 if (serializer->deserializeListObject(message: &newValue, ordering: V::propertyOrdering, it)) {
229 QList<V> list = previous.value<QList<V>>();
230 list.append(newValue);
231 previous.setValue(list);
232 }
233}
234
235/*!
236 \private
237 *
238 \brief default deserializer template for map of key K, value V
239 */
240template<typename K, typename V,
241 typename std::enable_if_t<!std::is_base_of<QProtobufMessage, V>::value, int> = 0>
242void deserializeMap(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it,
243 QVariant &previous)
244{
245 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
246
247 QHash<K, V> out = previous.value<QHash<K, V>>();
248 QVariant key = QVariant::fromValue<K>(K());
249 QVariant value = QVariant::fromValue<V>(V());
250
251 if (serializer->deserializeMapPair(key, value, it)) {
252 out[key.value<K>()] = value.value<V>();
253 previous = QVariant::fromValue<QHash<K, V>>(out);
254 }
255}
256
257/*!
258 \private
259 *
260 \brief default deserializer template for map of type key K, value V. Specialization for V
261 that inherits from QProtobufMessage
262 */
263template<typename K, typename V,
264 typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0>
265void deserializeMap(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it,
266 QVariant &previous)
267{
268 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
269
270 auto out = previous.value<QHash<K, V>>();
271 QVariant key = QVariant::fromValue<K>(K());
272 QVariant value = QVariant::fromValue<V *>(nullptr);
273
274 if (serializer->deserializeMapPair(key, value, it)) {
275 const auto valuePtr = value.value<V *>();
276 out[key.value<K>()] = valuePtr ? *valuePtr : V();
277 previous = QVariant::fromValue<QHash<K, V>>(out);
278 }
279}
280
281/*!
282 \private
283 *
284 \brief default deserializer template for enum type T
285 */
286template<typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
287void deserializeEnum(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it,
288 QVariant &to)
289{
290 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
291 QtProtobuf::int64 intValue;
292 if (serializer->deserializeEnum(value&: intValue, it))
293 to = QVariant::fromValue<T>(static_cast<T>(intValue._t));
294}
295
296/*!
297 \private
298 *
299 \brief default deserializer template for enumList type T
300 */
301template<typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
302void deserializeEnumList(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it,
303 QVariant &previous)
304{
305 Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null");
306 QList<QtProtobuf::int64> intList;
307 if (!serializer->deserializeEnumList(value&: intList, it))
308 return;
309 QList<T> enumList = previous.value<QList<T>>();
310 for (auto intValue : intList)
311 enumList.append(static_cast<T>(intValue._t));
312 previous = QVariant::fromValue<QList<T>>(enumList);
313}
314} // namespace QtProtobufPrivate
315
316template<typename T>
317inline void qRegisterProtobufType()
318{
319 T::registerTypes();
320 QtProtobufPrivate::registerOrdering(type: QMetaType::fromType<T>(), ordering: T::propertyOrdering);
321 QtProtobufPrivate::registerHandler(
322 type: QMetaType::fromType<T *>(),
323 handlers: { QtProtobufPrivate::serializeObject<T>, QtProtobufPrivate::deserializeObject<T> });
324 QtProtobufPrivate::registerHandler(
325 type: QMetaType::fromType<QList<T>>(),
326 handlers: { QtProtobufPrivate::serializeList<T>, QtProtobufPrivate::deserializeList<T> });
327}
328
329template<typename K, typename V>
330inline void qRegisterProtobufMapType()
331{
332 QtProtobufPrivate::registerHandler(
333 type: QMetaType::fromType<QHash<K, V>>(),
334 handlers: { QtProtobufPrivate::serializeMap<K, V>, QtProtobufPrivate::deserializeMap<K, V> });
335}
336
337#ifdef Q_QDOC
338template<typename T>
339inline void qRegisterProtobufEnumType();
340#else // !Q_QDOC
341template<typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
342inline void qRegisterProtobufEnumType()
343{
344 QtProtobufPrivate::registerHandler(
345 type: QMetaType::fromType<T>(),
346 handlers: { QtProtobufPrivate::serializeEnum<T>, QtProtobufPrivate::deserializeEnum<T> });
347 QtProtobufPrivate::registerHandler(
348 type: QMetaType::fromType<QList<T>>(),
349 handlers: { QtProtobufPrivate::serializeEnumList<T>, QtProtobufPrivate::deserializeEnumList<T> });
350}
351#endif // Q_QDOC
352
353QT_END_NAMESPACE
354#endif // QPROTOBUFSERIALIZER_H
355

source code of qtgrpc/src/protobuf/qprotobufserializer.h