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/FileUtil.h" |
16 | | #include "zserio/Traits.h" |
17 | | #include "zserio/Vector.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, |
140 | | int>::type = 0> |
141 | | BasicBitBuffer<ALLOC> serialize(T& object, ARGS&&... arguments) |
142 | 5 | { |
143 | 5 | return detail::serialize(object, ALLOC(), std::forward<ARGS>(arguments)...); |
144 | 5 | } |
145 | | |
146 | | /** |
147 | | * Serializes given generated enum to bit buffer. |
148 | | * |
149 | | * Example: |
150 | | * \code{.cpp} |
151 | | * #include <zserio/SerializeUtil.h> |
152 | | * |
153 | | * const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue; |
154 | | * const zserio::BitBuffer bitBuffer = zserio::serialize(enumValue); |
155 | | * \endcode |
156 | | * |
157 | | * \param enumValue Generated enum to serialize. |
158 | | * \param allocator Allocator to use to allocate bit buffer. |
159 | | * |
160 | | * \return Bit buffer containing the serialized enum. |
161 | | * |
162 | | * \throw CppRuntimeException When serialization fails. |
163 | | */ |
164 | | template <typename T, typename ALLOC = std::allocator<uint8_t>, |
165 | | typename std::enable_if<std::is_enum<T>::value, int>::type = 0> |
166 | | BasicBitBuffer<ALLOC> serialize(T enumValue, const ALLOC& allocator = ALLOC()) |
167 | 6 | { |
168 | 6 | BasicBitBuffer<ALLOC> bitBuffer(zserio::bitSizeOf(enumValue), allocator); |
169 | 6 | BitStreamWriter writer(bitBuffer); |
170 | 6 | zserio::write(writer, enumValue); |
171 | 6 | return bitBuffer; |
172 | 6 | } |
173 | | |
174 | | /** |
175 | | * Deserializes given bit buffer to instance of generated object. |
176 | | * |
177 | | * Example: |
178 | | * \code{.cpp} |
179 | | * #include <zserio/SerializeUtil.h> |
180 | | * |
181 | | * SomeZserioObject object; |
182 | | * const zserio::BitBuffer bitBuffer = zserio::serialize(object); |
183 | | * SomeZserioObject readObject = zserio::deserialize<SomeZserioObject>(bitBuffer); |
184 | | * \endcode |
185 | | * |
186 | | * \param bitBuffer Bit buffer to use. |
187 | | * \param arguments Object's actual parameters together with allocator for object's read constructor (optional). |
188 | | * |
189 | | * \return Generated object created from the given bit buffer. |
190 | | * |
191 | | * \throw CppRuntimeException When deserialization fails. |
192 | | */ |
193 | | template <typename T, typename ALLOC, typename... ARGS> |
194 | | typename std::enable_if<!std::is_enum<T>::value, T>::type deserialize( |
195 | | const BasicBitBuffer<ALLOC>& bitBuffer, ARGS&&... arguments) |
196 | 12 | { |
197 | 12 | BitStreamReader reader(bitBuffer); |
198 | 12 | return T(reader, std::forward<ARGS>(arguments)...); |
199 | 12 | } |
200 | | |
201 | | /** |
202 | | * Deserializes given bit buffer to instance of generated enum. |
203 | | * |
204 | | * Example: |
205 | | * \code{.cpp} |
206 | | * #include <zserio/SerializeUtil.h> |
207 | | * |
208 | | * const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue; |
209 | | * const zserio::BitBuffer bitBuffer = zserio::serialize(enumValue); |
210 | | * const SomeZserioEnum readEnumValue = zserio::deserialize<DummyEnum>(bitBuffer); |
211 | | * \endcode |
212 | | * |
213 | | * \param bitBuffer Bit buffer to use. |
214 | | * |
215 | | * \return Generated enum created from the given bit buffer. |
216 | | * |
217 | | * \throw CppRuntimeException When deserialization fails. |
218 | | */ |
219 | | template <typename T, typename ALLOC> |
220 | | typename std::enable_if<std::is_enum<T>::value, T>::type deserialize(const BasicBitBuffer<ALLOC>& bitBuffer) |
221 | 3 | { |
222 | 3 | BitStreamReader reader(bitBuffer); |
223 | 3 | return zserio::read<T>(reader); |
224 | 3 | } |
225 | | |
226 | | /** |
227 | | * Serializes given generated object to vector of bytes using given allocator. |
228 | | * |
229 | | * Before serialization, the method properly calls on the given zserio object methods `initialize()` |
230 | | * (if exits), `initializeChildren()` (if exists) and `initializeOffsets()`. |
231 | | * |
232 | | * Example: |
233 | | * \code{.cpp} |
234 | | * #include <zserio/SerializeUtil.h> |
235 | | * #include <zserio/pmr/PolymorphicAllocator.h> |
236 | | * |
237 | | * const zserio::pmr::PolymorphicAllocator<> allocator; |
238 | | * SomeZserioObject object(allocator); |
239 | | * const zserio::vector<uint8_t, zserio::pmr::PolymorphicAllocator<>> buffer = |
240 | | * zserio::serializeToBytes(object, allocator); |
241 | | * \endcode |
242 | | * |
243 | | * \param object Generated object to serialize. |
244 | | * \param allocator Allocator to use to allocate vector. |
245 | | * \param arguments Object's actual parameters for initialize() method (optional). |
246 | | * |
247 | | * \return Vector of bytes containing the serialized object. |
248 | | * |
249 | | * \throw CppRuntimeException When serialization fails. |
250 | | */ |
251 | | template <typename T, typename ALLOC, typename... ARGS, |
252 | | typename std::enable_if<!std::is_enum<T>::value && is_allocator<ALLOC>::value, int>::type = 0> |
253 | | vector<uint8_t, ALLOC> serializeToBytes(T& object, const ALLOC& allocator, ARGS&&... arguments) |
254 | 4 | { |
255 | 4 | const BasicBitBuffer<ALLOC> bitBuffer = |
256 | 4 | detail::serialize(object, allocator, std::forward<ARGS>(arguments)...); |
257 | | |
258 | 4 | return bitBuffer.getBytes(); |
259 | 4 | } |
260 | | |
261 | | /** |
262 | | * Serializes given generated object to vector of bytes using default allocator 'std::allocator<uint8_t>'. |
263 | | * |
264 | | * Before serialization, the method properly calls on the given zserio object methods `initialize()` |
265 | | * (if exits), `initializeChildren()` (if exists) and `initializeOffsets()`. |
266 | | * |
267 | | * However, it's still possible that not all bits of the last byte are used. In this case, only most |
268 | | * significant bits of the corresponding size are used. |
269 | | * |
270 | | * Example: |
271 | | * \code{.cpp} |
272 | | * #include <zserio/SerializeUtil.h> |
273 | | * |
274 | | * SomeZserioObject object; |
275 | | * const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(object); |
276 | | * \endcode |
277 | | * |
278 | | * \param object Generated object to serialize. |
279 | | * \param arguments Object's actual parameters for initialize() method (optional). |
280 | | * |
281 | | * \return Vector of bytes containing the serialized object. |
282 | | * |
283 | | * \throw CppRuntimeException When serialization fails. |
284 | | */ |
285 | | template <typename T, typename ALLOC = typename detail::allocator_chooser<T>::type, typename... ARGS, |
286 | | typename std::enable_if<!std::is_enum<T>::value && |
287 | | !is_first_allocator<typename std::decay<ARGS>::type...>::value, |
288 | | int>::type = 0> |
289 | | vector<uint8_t, ALLOC> serializeToBytes(T& object, ARGS&&... arguments) |
290 | 2 | { |
291 | 2 | const BasicBitBuffer<ALLOC> bitBuffer = |
292 | 2 | detail::serialize(object, ALLOC(), std::forward<ARGS>(arguments)...); |
293 | | |
294 | 2 | return bitBuffer.getBytes(); |
295 | 2 | } |
296 | | |
297 | | /** |
298 | | * Serializes given generated enum to vector of bytes. |
299 | | * |
300 | | * Example: |
301 | | * \code{.cpp} |
302 | | * #include <zserio/SerializeUtil.h> |
303 | | * |
304 | | * const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue; |
305 | | * const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(enumValue); |
306 | | * \endcode |
307 | | * |
308 | | * \param enumValue Generated enum to serialize. |
309 | | * \param allocator Allocator to use to allocate vector. |
310 | | * |
311 | | * \return Vector of bytes containing the serialized enum. |
312 | | * |
313 | | * \throw CppRuntimeException When serialization fails. |
314 | | */ |
315 | | template <typename T, typename ALLOC = std::allocator<uint8_t>, |
316 | | typename std::enable_if<std::is_enum<T>::value, int>::type = 0> |
317 | | vector<uint8_t, ALLOC> serializeToBytes(T enumValue, const ALLOC& allocator = ALLOC()) |
318 | 3 | { |
319 | 3 | const BasicBitBuffer<ALLOC> bitBuffer = serialize(enumValue, allocator); |
320 | | |
321 | 3 | return bitBuffer.getBytes(); |
322 | 3 | } |
323 | | |
324 | | /** |
325 | | * Deserializes given vector of bytes to instance of generated object. |
326 | | * |
327 | | * This method can potentially use all bits of the last byte even if not all of them were written during |
328 | | * serialization (because there is no way how to specify exact number of bits). Thus, it could allow reading |
329 | | * behind stream (possibly in case of damaged data). |
330 | | * |
331 | | * Example: |
332 | | * \code{.cpp} |
333 | | * #include <zserio/SerializeUtil.h> |
334 | | * |
335 | | * SomeZserioObject object; |
336 | | * const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(object); |
337 | | * SomeZserioObject readObject = zserio::deserializeFromBytes<SomeZserioObject>(buffer); |
338 | | * \endcode |
339 | | * |
340 | | * \param bitBuffer Vector of bytes to use. |
341 | | * \param arguments Object's actual parameters together with allocator for object's read constructor (optional). |
342 | | * |
343 | | * \return Generated object created from the given vector of bytes. |
344 | | * |
345 | | * \throw CppRuntimeException When deserialization fails. |
346 | | */ |
347 | | template <typename T, typename... ARGS> |
348 | | typename std::enable_if<!std::is_enum<T>::value, T>::type deserializeFromBytes( |
349 | | Span<const uint8_t> buffer, ARGS&&... arguments) |
350 | 9 | { |
351 | 9 | BitStreamReader reader(buffer); |
352 | 9 | return T(reader, std::forward<ARGS>(arguments)...); |
353 | 9 | } |
354 | | |
355 | | /** |
356 | | * Deserializes given vector of bytes to instance of generated enum. |
357 | | * |
358 | | * Example: |
359 | | * \code{.cpp} |
360 | | * #include <zserio/SerializeUtil.h> |
361 | | * |
362 | | * const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue; |
363 | | * const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(enumValue); |
364 | | * const SomeZserioEnum readEnumValue = zserio::deserializeFromBytes<DummyEnum>(buffer); |
365 | | * \endcode |
366 | | * |
367 | | * \param bitBuffer Vector of bytes to use. |
368 | | * |
369 | | * \return Generated enum created from the given vector of bytes. |
370 | | * |
371 | | * \throw CppRuntimeException When deserialization fails. |
372 | | */ |
373 | | template <typename T> |
374 | | typename std::enable_if<std::is_enum<T>::value, T>::type deserializeFromBytes(Span<const uint8_t> buffer) |
375 | 3 | { |
376 | 3 | BitStreamReader reader(buffer); |
377 | 3 | return zserio::read<T>(reader); |
378 | 3 | } |
379 | | |
380 | | /** |
381 | | * Serializes given generated object to file. |
382 | | * |
383 | | * Example: |
384 | | * \code{.cpp} |
385 | | * #include <zserio/SerializeUtil.h> |
386 | | * |
387 | | * SomeZserioObject object; |
388 | | * zserio::serializeToFile(object, "FileName.bin"); |
389 | | * \endcode |
390 | | * |
391 | | * \param object Generated object to serialize. |
392 | | * \param fileName File name to write. |
393 | | * |
394 | | * \throw CppRuntimeException When serialization fails. |
395 | | */ |
396 | | template <typename T, typename... ARGS> |
397 | | void serializeToFile(T& object, const std::string& fileName, ARGS&&... arguments) |
398 | 3 | { |
399 | 3 | const auto bitBuffer = serialize(object, std::forward<ARGS>(arguments)...); |
400 | 3 | writeBufferToFile(bitBuffer, fileName); |
401 | 3 | } |
402 | | |
403 | | /** |
404 | | * Deserializes given file contents to instance of generated object. |
405 | | * |
406 | | * Example: |
407 | | * \code{.cpp} |
408 | | * #include <zserio/SerializeUtil.h> |
409 | | * |
410 | | * const std::string fileName = "FileName.bin"; |
411 | | * SomeZserioObject object; |
412 | | * zserio::serializeToFile(object, fileName); |
413 | | * SomeZserioObject readObject = zserio::deserializeFromFile<SomeZserioObject>(fileName); |
414 | | * \endcode |
415 | | * |
416 | | * \note Please note that BitBuffer is always allocated using 'std::allocator<uint8_t>'. |
417 | | * |
418 | | * \param fileName File to use. |
419 | | * \param arguments Object's arguments (optional). |
420 | | * |
421 | | * \return Generated object created from the given file contents. |
422 | | * |
423 | | * \throw CppRuntimeException When deserialization fails. |
424 | | */ |
425 | | template <typename T, typename... ARGS> |
426 | | T deserializeFromFile(const std::string& fileName, ARGS&&... arguments) |
427 | 3 | { |
428 | 3 | const BitBuffer bitBuffer = readBufferFromFile(fileName); |
429 | 3 | return deserialize<T>(bitBuffer, std::forward<ARGS>(arguments)...); |
430 | 3 | } |
431 | | |
432 | | } // namespace zserio |
433 | | |
434 | | #endif // ZSERIO_SERIALIZE_UTIL_H_INC |