src/zserio/SerializeUtil.h
Line | Count | Source |
1 | | /** |
2 | | * \file |
3 | | * It provides help methods for serialization and deserialization of generated objects. |
4 | | * |
5 | | * These utilities are not used by generated code and they are provided only for user convenience. |
6 | | * |
7 | | * \note Please note that file operations allocate memory as needed and are not designed to use allocators. |
8 | | */ |
9 | | |
10 | | #ifndef ZSERIO_SERIALIZE_UTIL_H_INC |
11 | | #define ZSERIO_SERIALIZE_UTIL_H_INC |
12 | | |
13 | | #include "zserio/BitStreamReader.h" |
14 | | #include "zserio/BitStreamWriter.h" |
15 | | #include "zserio/Vector.h" |
16 | | #include "zserio/FileUtil.h" |
17 | | #include "zserio/Traits.h" |
18 | | |
19 | | namespace zserio |
20 | | { |
21 | | |
22 | | namespace detail |
23 | | { |
24 | | |
25 | | template <typename T> |
26 | | void initializeChildrenImpl(std::true_type, T& object) |
27 | 9 | { |
28 | 9 | object.initializeChildren(); |
29 | 9 | } |
30 | | |
31 | | template <typename T> |
32 | | void initializeChildrenImpl(std::false_type, T&) |
33 | | {} |
34 | | |
35 | | template <typename T> |
36 | | void initializeChildren(T& object) |
37 | 9 | { |
38 | 9 | initializeChildrenImpl(has_initialize_children<T>(), object); |
39 | 9 | } |
40 | | |
41 | | template <typename T, typename ...ARGS> |
42 | | void initializeImpl(std::true_type, T& object, ARGS&&... arguments) |
43 | 6 | { |
44 | 6 | object.initialize(std::forward<ARGS>(arguments)...); |
45 | 6 | } |
46 | | |
47 | | template <typename T> |
48 | | void initializeImpl(std::false_type, T& object) |
49 | 9 | { |
50 | 9 | initializeChildren(object); |
51 | 9 | } |
52 | | |
53 | | template <typename T, typename ...ARGS> |
54 | | void initialize(T& object, ARGS&&... arguments) |
55 | 15 | { |
56 | 15 | initializeImpl(has_initialize<T>(), object, std::forward<ARGS>(arguments)...); |
57 | 15 | } |
58 | | |
59 | | template <typename T, typename = void> |
60 | | struct allocator_chooser |
61 | | { |
62 | | using type = std::allocator<uint8_t>; |
63 | | }; |
64 | | |
65 | | template <typename T> |
66 | | struct allocator_chooser<T, detail::void_t<typename T::allocator_type>> |
67 | | { |
68 | | using type = typename T::allocator_type; |
69 | | }; |
70 | | |
71 | | // This implementation needs to be in detail because old MSVC compiler 2015 has problems with calling overload. |
72 | | template <typename T, typename ALLOC, typename ...ARGS> |
73 | | BasicBitBuffer<ALLOC> serialize(T& object, const ALLOC& allocator, ARGS&&... arguments) |
74 | 15 | { |
75 | 15 | detail::initialize(object, std::forward<ARGS>(arguments)...); |
76 | 15 | BasicBitBuffer<ALLOC> bitBuffer(object.initializeOffsets(), allocator); |
77 | 15 | BitStreamWriter writer(bitBuffer); |
78 | 15 | object.write(writer); |
79 | 15 | return bitBuffer; |
80 | 15 | } |
81 | | |
82 | | } // namespace detail |
83 | | |
84 | | /** |
85 | | * Serializes given generated object to bit buffer using given allocator. |
86 | | * |
87 | | * Before serialization, the method properly calls on the given zserio object methods `initialize()` |
88 | | * (if exits), `initializeChildren()` (if exists) and `initializeOffsets()`. |
89 | | * |
90 | | * Example: |
91 | | * \code{.cpp} |
92 | | * #include <zserio/SerializeUtil.h> |
93 | | * #include <zserio/pmr/PolymorphicAllocator.h> |
94 | | * |
95 | | * const zserio::pmr::PolymorphicAllocator<> allocator; |
96 | | * SomeZserioObject object(allocator); |
97 | | * const zserio::BasicBitBuffer<zserio::pmr::PolymorphicAllocator<>> bitBuffer = |
98 | | * zserio::serialize(object, allocator); |
99 | | * \endcode |
100 | | * |
101 | | * \param object Generated object to serialize. |
102 | | * \param allocator Allocator to use to allocate bit buffer. |
103 | | * \param arguments Object's actual parameters for initialize() method (optional). |
104 | | * |
105 | | * \return Bit buffer containing the serialized object. |
106 | | * |
107 | | * \throw CppRuntimeException When serialization fails. |
108 | | */ |
109 | | template <typename T, typename ALLOC, typename ...ARGS, |
110 | | typename std::enable_if<!std::is_enum<T>::value && is_allocator<ALLOC>::value, int>::type = 0> |
111 | | BasicBitBuffer<ALLOC> serialize(T& object, const ALLOC& allocator, ARGS&&... arguments) |
112 | 4 | { |
113 | 4 | return detail::serialize(object, allocator, std::forward<ARGS>(arguments)...); |
114 | 4 | } |
115 | | |
116 | | /** |
117 | | * Serializes given generated object to bit buffer using default allocator 'std::allocator<uint8_t>'. |
118 | | * |
119 | | * Before serialization, the method properly calls on the given zserio object methods `initialize()` |
120 | | * (if exits), `initializeChildren()` (if exists) and `initializeOffsets()`. |
121 | | * |
122 | | * Example: |
123 | | * \code{.cpp} |
124 | | * #include <zserio/SerializeUtil.h> |
125 | | * |
126 | | * SomeZserioObject object; |
127 | | * const zserio::BitBuffer bitBuffer = zserio::serialize(object); |
128 | | * \endcode |
129 | | * |
130 | | * \param object Generated object to serialize. |
131 | | * \param arguments Object's actual parameters for initialize() method (optional). |
132 | | * |
133 | | * \return Bit buffer containing the serialized object. |
134 | | * |
135 | | * \throw CppRuntimeException When serialization fails. |
136 | | */ |
137 | | template <typename T, typename ALLOC = typename detail::allocator_chooser<T>::type, typename ...ARGS, |
138 | | typename std::enable_if<!std::is_enum<T>::value && |
139 | | !is_first_allocator<typename std::decay<ARGS>::type...>::value, int>::type = 0> |
140 | | BasicBitBuffer<ALLOC> serialize(T& object, ARGS&&... arguments) |
141 | 5 | { |
142 | 5 | return detail::serialize(object, ALLOC(), std::forward<ARGS>(arguments)...); |
143 | 5 | } |
144 | | |
145 | | /** |
146 | | * Serializes given generated enum to bit buffer. |
147 | | * |
148 | | * Example: |
149 | | * \code{.cpp} |
150 | | * #include <zserio/SerializeUtil.h> |
151 | | * |
152 | | * const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue; |
153 | | * const zserio::BitBuffer bitBuffer = zserio::serialize(enumValue); |
154 | | * \endcode |
155 | | * |
156 | | * \param enumValue Generated enum to serialize. |
157 | | * \param allocator Allocator to use to allocate bit buffer. |
158 | | * |
159 | | * \return Bit buffer containing the serialized enum. |
160 | | * |
161 | | * \throw CppRuntimeException When serialization fails. |
162 | | */ |
163 | | template <typename T, typename ALLOC = std::allocator<uint8_t>, |
164 | | typename std::enable_if<std::is_enum<T>::value, int>::type = 0> |
165 | | BasicBitBuffer<ALLOC> serialize(T enumValue, const ALLOC& allocator = ALLOC()) |
166 | 6 | { |
167 | 6 | BasicBitBuffer<ALLOC> bitBuffer(zserio::bitSizeOf(enumValue), allocator); |
168 | 6 | BitStreamWriter writer(bitBuffer); |
169 | 6 | zserio::write(writer, enumValue); |
170 | 6 | return bitBuffer; |
171 | 6 | } |
172 | | |
173 | | /** |
174 | | * Deserializes given bit buffer to instance of generated object. |
175 | | * |
176 | | * Example: |
177 | | * \code{.cpp} |
178 | | * #include <zserio/SerializeUtil.h> |
179 | | * |
180 | | * SomeZserioObject object; |
181 | | * const zserio::BitBuffer bitBuffer = zserio::serialize(object); |
182 | | * SomeZserioObject readObject = zserio::deserialize<SomeZserioObject>(bitBuffer); |
183 | | * \endcode |
184 | | * |
185 | | * \param bitBuffer Bit buffer to use. |
186 | | * \param arguments Object's actual parameters together with allocator for object's read constructor (optional). |
187 | | * |
188 | | * \return Generated object created from the given bit buffer. |
189 | | * |
190 | | * \throw CppRuntimeException When deserialization fails. |
191 | | */ |
192 | | template <typename T, typename ALLOC, typename ...ARGS> |
193 | | typename std::enable_if<!std::is_enum<T>::value, T>::type deserialize( |
194 | | const BasicBitBuffer<ALLOC>& bitBuffer, ARGS&&... arguments) |
195 | 12 | { |
196 | 12 | BitStreamReader reader(bitBuffer); |
197 | 12 | return T(reader, std::forward<ARGS>(arguments)...); |
198 | 12 | } |
199 | | |
200 | | /** |
201 | | * Deserializes given bit buffer to instance of generated enum. |
202 | | * |
203 | | * Example: |
204 | | * \code{.cpp} |
205 | | * #include <zserio/SerializeUtil.h> |
206 | | * |
207 | | * const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue; |
208 | | * const zserio::BitBuffer bitBuffer = zserio::serialize(enumValue); |
209 | | * const SomeZserioEnum readEnumValue = zserio::deserialize<DummyEnum>(bitBuffer); |
210 | | * \endcode |
211 | | * |
212 | | * \param bitBuffer Bit buffer to use. |
213 | | * |
214 | | * \return Generated enum created from the given bit buffer. |
215 | | * |
216 | | * \throw CppRuntimeException When deserialization fails. |
217 | | */ |
218 | | template <typename T, typename ALLOC> |
219 | | typename std::enable_if<std::is_enum<T>::value, T>::type deserialize(const BasicBitBuffer<ALLOC>& bitBuffer) |
220 | 3 | { |
221 | 3 | BitStreamReader reader(bitBuffer); |
222 | 3 | return zserio::read<T>(reader); |
223 | 3 | } |
224 | | |
225 | | /** |
226 | | * Serializes given generated object to vector of bytes using given allocator. |
227 | | * |
228 | | * Before serialization, the method properly calls on the given zserio object methods `initialize()` |
229 | | * (if exits), `initializeChildren()` (if exists) and `initializeOffsets()`. |
230 | | * |
231 | | * Example: |
232 | | * \code{.cpp} |
233 | | * #include <zserio/SerializeUtil.h> |
234 | | * #include <zserio/pmr/PolymorphicAllocator.h> |
235 | | * |
236 | | * const zserio::pmr::PolymorphicAllocator<> allocator; |
237 | | * SomeZserioObject object(allocator); |
238 | | * const zserio::vector<uint8_t, zserio::pmr::PolymorphicAllocator<>> buffer = |
239 | | * zserio::serializeToBytes(object, allocator); |
240 | | * \endcode |
241 | | * |
242 | | * \param object Generated object to serialize. |
243 | | * \param allocator Allocator to use to allocate vector. |
244 | | * \param arguments Object's actual parameters for initialize() method (optional). |
245 | | * |
246 | | * \return Vector of bytes containing the serialized object. |
247 | | * |
248 | | * \throw CppRuntimeException When serialization fails. |
249 | | */ |
250 | | template <typename T, typename ALLOC, typename ...ARGS, |
251 | | typename std::enable_if<!std::is_enum<T>::value && is_allocator<ALLOC>::value, int>::type = 0> |
252 | | vector<uint8_t, ALLOC> serializeToBytes(T& object, const ALLOC& allocator, ARGS&&... arguments) |
253 | 4 | { |
254 | 4 | const BasicBitBuffer<ALLOC> bitBuffer = detail::serialize(object, allocator, |
255 | 4 | std::forward<ARGS>(arguments)...); |
256 | | |
257 | 4 | return bitBuffer.getBytes(); |
258 | 4 | } |
259 | | |
260 | | /** |
261 | | * Serializes given generated object to vector of bytes using default allocator 'std::allocator<uint8_t>'. |
262 | | * |
263 | | * Before serialization, the method properly calls on the given zserio object methods `initialize()` |
264 | | * (if exits), `initializeChildren()` (if exists) and `initializeOffsets()`. |
265 | | * |
266 | | * However, it's still possible that not all bits of the last byte are used. In this case, only most |
267 | | * significant bits of the corresponding size are used. |
268 | | * |
269 | | * Example: |
270 | | * \code{.cpp} |
271 | | * #include <zserio/SerializeUtil.h> |
272 | | * |
273 | | * SomeZserioObject object; |
274 | | * const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(object); |
275 | | * \endcode |
276 | | * |
277 | | * \param object Generated object to serialize. |
278 | | * \param arguments Object's actual parameters for initialize() method (optional). |
279 | | * |
280 | | * \return Vector of bytes containing the serialized object. |
281 | | * |
282 | | * \throw CppRuntimeException When serialization fails. |
283 | | */ |
284 | | template <typename T, typename ALLOC = typename detail::allocator_chooser<T>::type, typename ...ARGS, |
285 | | typename std::enable_if<!std::is_enum<T>::value && |
286 | | !is_first_allocator<typename std::decay<ARGS>::type...>::value, int>::type = 0> |
287 | | vector<uint8_t, ALLOC> serializeToBytes(T& object, ARGS&&... arguments) |
288 | 2 | { |
289 | 2 | const BasicBitBuffer<ALLOC> bitBuffer = detail::serialize(object, ALLOC(), |
290 | 2 | std::forward<ARGS>(arguments)...); |
291 | | |
292 | 2 | return bitBuffer.getBytes(); |
293 | 2 | } |
294 | | |
295 | | /** |
296 | | * Serializes given generated enum to vector of bytes. |
297 | | * |
298 | | * Example: |
299 | | * \code{.cpp} |
300 | | * #include <zserio/SerializeUtil.h> |
301 | | * |
302 | | * const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue; |
303 | | * const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(enumValue); |
304 | | * \endcode |
305 | | * |
306 | | * \param enumValue Generated enum to serialize. |
307 | | * \param allocator Allocator to use to allocate vector. |
308 | | * |
309 | | * \return Vector of bytes containing the serialized enum. |
310 | | * |
311 | | * \throw CppRuntimeException When serialization fails. |
312 | | */ |
313 | | template <typename T, typename ALLOC = std::allocator<uint8_t>, |
314 | | typename std::enable_if<std::is_enum<T>::value, int>::type = 0> |
315 | | vector<uint8_t, ALLOC> serializeToBytes(T enumValue, const ALLOC& allocator = ALLOC()) |
316 | 3 | { |
317 | 3 | const BasicBitBuffer<ALLOC> bitBuffer = serialize(enumValue, allocator); |
318 | | |
319 | 3 | return bitBuffer.getBytes(); |
320 | 3 | } |
321 | | |
322 | | /** |
323 | | * Deserializes given vector of bytes to instance of generated object. |
324 | | * |
325 | | * This method can potentially use all bits of the last byte even if not all of them were written during |
326 | | * serialization (because there is no way how to specify exact number of bits). Thus, it could allow reading |
327 | | * behind stream (possibly in case of damaged data). |
328 | | * |
329 | | * Example: |
330 | | * \code{.cpp} |
331 | | * #include <zserio/SerializeUtil.h> |
332 | | * |
333 | | * SomeZserioObject object; |
334 | | * const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(object); |
335 | | * SomeZserioObject readObject = zserio::deserializeFromBytes<SomeZserioObject>(buffer); |
336 | | * \endcode |
337 | | * |
338 | | * \param bitBuffer Vector of bytes to use. |
339 | | * \param arguments Object's actual parameters together with allocator for object's read constructor (optional). |
340 | | * |
341 | | * \return Generated object created from the given vector of bytes. |
342 | | * |
343 | | * \throw CppRuntimeException When deserialization fails. |
344 | | */ |
345 | | template <typename T, typename ...ARGS> |
346 | | typename std::enable_if<!std::is_enum<T>::value, T>::type deserializeFromBytes( |
347 | | Span<const uint8_t> buffer, ARGS&&... arguments) |
348 | 9 | { |
349 | 9 | BitStreamReader reader(buffer); |
350 | 9 | return T(reader, std::forward<ARGS>(arguments)...); |
351 | 9 | } |
352 | | |
353 | | /** |
354 | | * Deserializes given vector of bytes to instance of generated enum. |
355 | | * |
356 | | * Example: |
357 | | * \code{.cpp} |
358 | | * #include <zserio/SerializeUtil.h> |
359 | | * |
360 | | * const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue; |
361 | | * const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(enumValue); |
362 | | * const SomeZserioEnum readEnumValue = zserio::deserializeFromBytes<DummyEnum>(buffer); |
363 | | * \endcode |
364 | | * |
365 | | * \param bitBuffer Vector of bytes to use. |
366 | | * |
367 | | * \return Generated enum created from the given vector of bytes. |
368 | | * |
369 | | * \throw CppRuntimeException When deserialization fails. |
370 | | */ |
371 | | template <typename T> |
372 | | typename std::enable_if<std::is_enum<T>::value, T>::type deserializeFromBytes(Span<const uint8_t> buffer) |
373 | 3 | { |
374 | 3 | BitStreamReader reader(buffer); |
375 | 3 | return zserio::read<T>(reader); |
376 | 3 | } |
377 | | |
378 | | /** |
379 | | * Serializes given generated object to file. |
380 | | * |
381 | | * Example: |
382 | | * \code{.cpp} |
383 | | * #include <zserio/SerializeUtil.h> |
384 | | * |
385 | | * SomeZserioObject object; |
386 | | * zserio::serializeToFile(object, "FileName.bin"); |
387 | | * \endcode |
388 | | * |
389 | | * \param object Generated object to serialize. |
390 | | * \param fileName File name to write. |
391 | | * |
392 | | * \throw CppRuntimeException When serialization fails. |
393 | | */ |
394 | | template <typename T, typename ...ARGS> |
395 | | void serializeToFile(T& object, const std::string& fileName, ARGS&&... arguments) |
396 | 3 | { |
397 | 3 | const auto bitBuffer = serialize(object, std::forward<ARGS>(arguments)...); |
398 | 3 | writeBufferToFile(bitBuffer, fileName); |
399 | 3 | } |
400 | | |
401 | | /** |
402 | | * Deserializes given file contents to instance of generated object. |
403 | | * |
404 | | * Example: |
405 | | * \code{.cpp} |
406 | | * #include <zserio/SerializeUtil.h> |
407 | | * |
408 | | * const std::string fileName = "FileName.bin"; |
409 | | * SomeZserioObject object; |
410 | | * zserio::serializeToFile(object, fileName); |
411 | | * SomeZserioObject readObject = zserio::deserializeFromFile<SomeZserioObject>(fileName); |
412 | | * \endcode |
413 | | * |
414 | | * \note Please note that BitBuffer is always allocated using 'std::allocator<uint8_t>'. |
415 | | * |
416 | | * \param fileName File to use. |
417 | | * \param arguments Object's arguments (optional). |
418 | | * |
419 | | * \return Generated object created from the given file contents. |
420 | | * |
421 | | * \throw CppRuntimeException When deserialization fails. |
422 | | */ |
423 | | template <typename T, typename ...ARGS> |
424 | | T deserializeFromFile(const std::string& fileName, ARGS&&... arguments) |
425 | 3 | { |
426 | 3 | const BitBuffer bitBuffer = readBufferFromFile(fileName); |
427 | 3 | return deserialize<T>(bitBuffer, std::forward<ARGS>(arguments)...); |
428 | 3 | } |
429 | | |
430 | | } // namespace zserio |
431 | | |
432 | | #endif // ZSERIO_SERIALIZE_UTIL_H_INC |