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 | |
21 | QT_BEGIN_NAMESPACE |
22 | |
23 | namespace QtProtobufPrivate { |
24 | class QProtobufSelfcheckIterator; |
25 | } // namespace QtProtobufPrivate |
26 | |
27 | class QProtobufSerializerPrivate; |
28 | class Q_PROTOBUF_EXPORT QProtobufSerializer : public QAbstractProtobufSerializer |
29 | { |
30 | Q_DISABLE_COPY_MOVE(QProtobufSerializer) |
31 | public: |
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 | |
81 | private: |
82 | std::unique_ptr<QProtobufSerializerPrivate> d_ptr; |
83 | }; |
84 | |
85 | namespace QtProtobufPrivate { |
86 | |
87 | using Serializer = void (*)(const QProtobufSerializer *, const QVariant &, |
88 | const QProtobufPropertyOrderingInfo &, QByteArray &); |
89 | using 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 | */ |
97 | struct SerializationHandler |
98 | { |
99 | Serializer serializer = nullptr; /*!< serializer assigned to class */ |
100 | Deserializer deserializer = nullptr; /*!< deserializer assigned to class */ |
101 | }; |
102 | |
103 | extern Q_PROTOBUF_EXPORT SerializationHandler findHandler(QMetaType type); |
104 | extern 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 | */ |
110 | template<typename T, |
111 | typename std::enable_if_t<std::is_base_of<QProtobufMessage, T>::value, int> = 0> |
112 | void 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 | */ |
123 | template<typename V, |
124 | typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0> |
125 | void 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 | */ |
138 | template<typename K, typename V, |
139 | typename std::enable_if_t<!std::is_base_of<QProtobufMessage, V>::value, int> = 0> |
140 | void 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 | */ |
155 | template<typename K, typename V, |
156 | typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0> |
157 | void 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 | */ |
171 | template<typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0> |
172 | void 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 | */ |
183 | template<typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0> |
184 | void 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 | */ |
199 | template<typename T, |
200 | typename std::enable_if_t<std::is_base_of<QProtobufMessage, T>::value, int> = 0> |
201 | void 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 | */ |
220 | template<typename V, |
221 | typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0> |
222 | void 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 | */ |
240 | template<typename K, typename V, |
241 | typename std::enable_if_t<!std::is_base_of<QProtobufMessage, V>::value, int> = 0> |
242 | void 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 | */ |
263 | template<typename K, typename V, |
264 | typename std::enable_if_t<std::is_base_of<QProtobufMessage, V>::value, int> = 0> |
265 | void 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 | */ |
286 | template<typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0> |
287 | void 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 | */ |
301 | template<typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0> |
302 | void 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 | |
316 | template<typename T> |
317 | inline 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 | |
329 | template<typename K, typename V> |
330 | inline 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 |
338 | template<typename T> |
339 | inline void qRegisterProtobufEnumType(); |
340 | #else // !Q_QDOC |
341 | template<typename T, typename std::enable_if_t<std::is_enum<T>::value, int> = 0> |
342 | inline 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 | |
353 | QT_END_NAMESPACE |
354 | #endif // QPROTOBUFSERIALIZER_H |
355 | |