-
Notifications
You must be signed in to change notification settings - Fork 89
/
palMsgPack.h
633 lines (555 loc) · 26.2 KB
/
palMsgPack.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
/*
***********************************************************************************************************************
*
* Copyright (c) 2018-2024 Advanced Micro Devices, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************************************************************************/
/**
***********************************************************************************************************************
* @file palMsgPack.h
* @brief PAL MessagePack reader and writer utility class declarations.
***********************************************************************************************************************
*/
#pragma once
#include "palHashMap.h"
#include "palVector.h"
#include "palSparseVector.h"
#include "palStringView.h"
#include "palSysMemory.h"
#include <type_traits>
#include "cwpack.h"
namespace Util
{
Result TranslateCwpReturnCode(int32 returnCode);
/**
***********************************************************************************************************************
* @brief Utility class that emits a MsgPack blob.
*
* See http://www.msgpack.org/ for a complete description of the MsgPack standard.
*
* NOTE: If an error is encountered, the result code gets saved, and all subsequent pack method calls become a no-op and
* just return the saved result code. Therefore, checking the result between pack method calls is not necessary.
***********************************************************************************************************************
*/
class MsgPackWriter
{
public:
/// Constructor.
///
/// @param [in] pAllocator The MsgPackWriter will use this Allocator to create and resize the output buffer.
template <typename Allocator>
explicit MsgPackWriter(Allocator*const pAllocator);
/// Alternate constructor where the MsgPackWriter writes to a fixed-size, user-managed buffer.
///
/// @warning The buffer will not be grown in this mode.
///
/// @param [in/out] pBuffer The buffer to write the MsgPack blob into.
/// @param [in] sizeInBytes Size in bytes of the buffer.
MsgPackWriter(void* pBuffer, uint32 sizeInBytes);
/// Destructor.
~MsgPackWriter()
{
if ((m_pfnFree != nullptr) && (m_context.client_data != nullptr))
{
(*m_pfnFree)(&m_context);
}
}
/// Returns a read-only pointer to the MsgPack buffer.
const void* GetBuffer() const
{
PAL_ASSERT((m_context.return_code == CWP_RC_OK) && (m_containerNumItemsRemaining == 0));
return m_context.start;
}
/// Returns the used size (not overall capacity) in bytes of the MsgPack buffer.
uint32 GetSize() const { return static_cast<uint32>(Util::VoidPtrDiff(m_context.current, m_context.start)); }
/// Reserves the specified number of bytes in the buffer.
///
/// @param [in] newSizeInBytes Size of the space to reserve.
///
/// @returns Success if successful, ErrorOutOfMemory is memory allocation fails.
Result Reserve(uint32 newSizeInBytes);
/// Appends the contents of a MsgPack token stream created by another MsgPackWriter to this one.
///
/// @param [in] src Reference to the other MsgPackWriter to copy from.
///
/// @returns Success if successful, ErrorOutOfMemory if memory allocation fails.
Result Append(const MsgPackWriter& src);
/// Resets the state of the writer, allowing it to be reused to write another MsgPack blob.
void Reset();
/// Packs a nil element.
///
/// @returns Success if successful, ErrorOutOfMemory if memory allocation fails.
Result PackNil()
{
cw_pack_nil(&m_context);
return CountAndStatus(1);
}
///@{
/// Packs a scalar element.
///
/// @param [in] value The value to write.
void Pack(bool value)
{
cw_pack_boolean(&m_context, value);
CountItems(1);
}
void Pack(char value) { PackSigned(value); }
void Pack(uint8 value) { PackUnsigned(value); }
void Pack(uint16 value) { PackUnsigned(value); }
void Pack(uint32 value) { PackUnsigned(value); }
void Pack(uint64 value) { PackUnsigned(value); }
void Pack(int8 value) { PackSigned(value); }
void Pack(int16 value) { PackSigned(value); }
void Pack(int32 value) { PackSigned(value); }
void Pack(int64 value) { PackSigned(value); }
void Pack(float value)
{
cw_pack_float(&m_context, value);
CountItems(1);
}
void Pack(double value)
{
cw_pack_double(&m_context, value);
CountItems(1);
}
///@}
/// Packs a scalar element.
///
/// @param [in] value The value to write.
template <typename T>
void Pack(T value)
{
Pack(value);
}
/// Packs a string element.
///
/// @param [in] pString The null-terminated string to write.
/// @param [in] length Length of the string, excluding null-terminator.
void PackString(const char* pString, uint32 length)
{
cw_pack_str(&m_context, pString, length);
CountItems(1);
}
/// Packs a string element from a @ref StringView object.
///
/// @param [in] string The StringView to pack.
void PackString(const StringView<char>& string) { PackString(string.Data(), string.Length()); }
/// Packs a string element from a string literal as input.
///
/// @param [in] str The null-terminated string to write.
template <size_t N>
void Pack(const char (&string)[N]) { PackString(&string[0], N - 1); }
/// Packs an array of scalar elements.
///
/// @param [in] pArray The beginning of the array to write.
/// @param [in] numElements How many elements wide the array is.
///
/// @returns Success if successful, ErrorOutOfMemory if memory allocation fails.
template <typename T>
Result PackArray(const T* pArray, uint32 numElements);
/// Packs an array of scalar elements.
///
/// @param [in] pArray The beginning of the array to write.
/// @param [in] numElements How many elements wide the array is.
template <typename T>
void PackArray(const T* pArray, uint32 numElements, Result* pResult)
{
if (*pResult == Result::Success)
{
*pResult = PackArray(pArray, numElements);
}
}
/// Packs an array of scalar elements (bools, ints, uints, or floats) from a C-style array as input.
///
/// @param [in] array Reference to the C-style source array.
template <typename T, size_t N>
void Pack(const T (&array)[N]) { PackArray(&array[0], static_cast<uint32>(N)); }
/// Packs a binary blob element.
///
/// @param [in] pBuffer Pointer to a buffer with data to be written.
/// @param [in] sizeInBytes Size of the buffer in bytes.
void Pack(const void* pBuffer, uint32 sizeInBytes)
{
cw_pack_bin(&m_context, pBuffer, sizeInBytes);
CountItems(1);
}
/// Packs an object as a raw binary encoding.
///
/// @param [in] src Object to pack as binary.
template <typename T>
void PackBinary(const T& src) { Pack(static_cast<const void*>(&src), sizeof(src)); }
/// Packs a user-extended typed blob element.
///
/// @param [in] type User-extended type ID as an 8-bit signed integer.
/// @param [in] pBuffer Pointer to a buffer with data to be written.
/// @param [in] sizeInBytes Size of the buffer in bytes.
void Pack(int8 type, const void* pBuffer, uint32 sizeInBytes)
{
cw_pack_ext(&m_context, type, pBuffer, sizeInBytes);
CountItems(1);
}
/// Packs an object as a user-extended typed element.
///
/// @param [in] type User-extended type ID as an 8-bit signed integer.
/// @param [in] src Object to pack.
template <typename T>
void Pack(int8 type, const T& src) { Pack(type, static_cast<const void*>(&src), sizeof(src)); }
/// Packs an array element from a Vector.
///
/// @param [in] vector Reference to the Vector whose contents are to be packed.
///
/// @returns Success if successful, ErrorOutOfMemory if memory allocation fails.
template <typename T, uint32 DefaultCapacity, typename Allocator>
void Pack(const Vector<T, DefaultCapacity, Allocator>& vector);
/// Packs a map element from a HashMap.
///
/// @param [in] map Reference to the HashMap whose contents are to be packed.
///
/// @returns Success if successful, ErrorOutOfMemory if memory allocation fails.
template <typename Key,
typename Value,
typename Allocator,
template<typename> class HashFunc,
template<typename> class EqualFunc,
typename AllocFunc,
size_t GroupSize>
Result Pack(const HashMap<Key, Value, Allocator, HashFunc, EqualFunc, AllocFunc, GroupSize>& map);
/// Creates an array from the contents of an existing MsgPack token stream which was created by another
/// MsgPackWriter object.
///
/// @param [in] src Reference to the other MsgPackWriter to copy from.
///
/// @returns Success if successful, ErrorOutOfMemory if memory allocation fails.
Result AppendArray(const MsgPackWriter& src);
/// Creates an array from the contents of an existing MsgPack token stream which was created by another
/// MsgPackWriter object.
///
/// @param [in] src Reference to the other MsgPackWriter to copy from.
/// @param [in,out] pResult Result code returned from this function if Success is passed in.
void AppendArray(const MsgPackWriter& src, Result* pResult)
{
if (*pResult == Result::Success)
{
*pResult = AppendArray(src);
}
}
/// Creates a map from the contents of an existing MsgPack token stream which was created by another
/// MsgPackWriter object.
///
/// @param [in] src Reference to the other MsgPackWriter to copy from.
///
/// @returns Success if successful, ErrorOutOfMemory if memory allocation fails.
Result AppendMap(const MsgPackWriter& src);
/// Convenience function that combines two Pack() calls. Useful for manually packing a map.
///
/// @param [in] first First element to pack (key).
/// @param [in] second Second element to pack (value).
template <typename T1, typename T2>
void PackPair(const T1& first, const T2& second)
{
Pack(first);
Pack(second);
}
/// Declares the beginning of a fixed-size array, with the exact number of elements specified.
///
/// @param [in] numElements Exact number of elements this array contains.
///
/// @returns Success if successful, ErrorOutOfMemory if memory allocation fails.
Result DeclareArray(uint32 numElements);
/// Declares the beginning of a fixed-size map, with the exact number of elements specified.
///
/// @param [in] numElements Exact number of (key, value) pairs this map contains.
///
/// @returns Success if successful, ErrorOutOfMemory if memory allocation fails.
Result DeclareMap(uint32 numElements);
/// Returns the number of items written so far at the "root" level - entire containers count as a single item.
/// This value is appropriate for DeclareArray(), and 0.5x this value is appropriate for DeclareMap().
uint32 NumItems() const { return m_numItems; }
/// Gets the status of the writer.
///
/// @returns Success if no errors have been encountered, ErrorOutOfMemory if a memory allocation failed,
/// ErrorInvalidValue if malformed input was provided, ErrorUnknown otherwise.
Result GetStatus() const { return TranslateCwpReturnCode(m_context.return_code); }
private:
Result PackSigned(int64 value)
{
cw_pack_signed(&m_context, value);
return CountAndStatus(1);
}
Result PackUnsigned(uint64 value)
{
cw_pack_unsigned(&m_context, value);
return CountAndStatus(1);
}
void CountItems(uint32 num);
Result CountAndStatus(uint32 num)
{
CountItems(num);
return GetStatus();
}
template <typename Allocator>
static void FreeBuffer(cw_pack_context* pContext)
{ PAL_FREE(pContext->start, static_cast<Allocator*>(pContext->client_data)); }
using FreeBufferFunc = void(cw_pack_context*);
/// Overflow handler callback provided to CWPack.
template <typename Allocator>
static int32 CWP_CALL GrowBuffer(cw_pack_context* pContext, unsigned long requestedNumBytesToAdd);
/// Writer buffer is allocated with, and grown in multiples of, this size.
static constexpr uint32 BufferAllocSize = 8192;
cw_pack_context m_context;
FreeBufferFunc* m_pfnFree;
uint32 m_numItems;
uint32 m_containerNumItemsRemaining;
PAL_DISALLOW_DEFAULT_CTOR(MsgPackWriter);
PAL_DISALLOW_COPY_AND_ASSIGN(MsgPackWriter);
};
/**
***********************************************************************************************************************
* @brief Iterator-like utility class that parses in a MsgPack blob and translates it to C++ types.
*
* See http://www.msgpack.org/ for a complete description of the MsgPack standard.
*
* NOTE: Non-MsgPack errors resulting from unpack calls do not get saved to the internal state, although other errors
* do. That means unlike with the MsgPackWriter class, you will need to check the result between method calls.
***********************************************************************************************************************
*/
class MsgPackReader
{
public:
/// Constructor.
MsgPackReader() : m_context{} {}
/// Initializes the reader's state with the provided buffer as the input MsgPack to read from.
///
/// @returns Success if successful, ErrorInvalidValue if input is not valid MsgPack.
Result InitFromBuffer(const void* pBuffer, uint32 sizeInBytes)
{
cw_unpack_context_init(&m_context, pBuffer, sizeInBytes, nullptr, nullptr);
return Next();
}
/// Gets the current item token.
///
/// @returns A const reference to the current item token.
const cwpack_item& Get() const
{
PAL_ASSERT(GetStatus() == Result::Success);
return m_context.item;
}
/// Gets the current item token's type.
cwpack_item_types Type() const { return Get().type; }
/// Advances the reader to the next item token.
///
/// @returns Success if successful, Eof if the end of the buffer has been reached, ErrorInvalidValue if input
/// is not valid MsgPack.
Result Next()
{
cw_unpack_next(&m_context);
return GetStatus();
}
/// Advances the reader to the next item token, and sanity checks that it is an item with the given type.
///
/// @param [in] expectedType The type the next item is expected to be.
///
/// @returns Success if successful, ErrorInvalidValue if the next item's type does not match @ref expectedType,
/// the end of the buffer has been reached, or the input is not valid MsgPack.
Result Next(cwpack_item_types expectedType)
{
return ((Next() == Result::Success) && (m_context.item.type == expectedType)) ? Result::Success
: Result::ErrorInvalidValue;
}
/// Advances the reader to the next item token, and sanity checks that it is an array with the given size.
///
/// @param [in] expectedSize The size the next array is supposed to be.
///
/// @returns - Success if successful, ErrorInvalidValue if the next item is not an array of the given size,
/// the end of the buffer has been reached, or the input is not valid MsgPack.
Result NextArray(uint32 expectedSize)
{
return (Next(CWP_ITEM_ARRAY) == Result::Success) &&
(m_context.item.as.array.size == expectedSize) ? Result::Success : Result::ErrorInvalidValue;
}
/// Skips ahead by the specified number of elements. Skipping a container also skips all of its elements.
///
/// @param [in] numElements Number of elements to be skipped.
///
/// @returns Success if successful, Eof if the end of the buffer has been reached, ErrorInvalidValue if input
/// is not valid MsgPack.
Result Skip(int32 numElements)
{
cw_skip_items(&m_context, numElements);
return GetStatus();
}
/// Returns the position (in bytes) of the next item the reader would unpack.
uint32 Tell() const { return static_cast<uint32>(VoidPtrDiff(m_context.current, m_context.start)); }
/// Seeks the reader's position to the specified offset (in bytes) and attempts to unpack the next item there.
///
/// @param [in] offset Offset in bytes to seek to. Valid values may be obtained from @ref Tell().
/// A value larger than the size of the buffer seeks to the end of the buffer.
///
/// @returns Success if successful, Eof is the end of the buffer has been reached, ErrorInvalidValue if input
/// is not valid MsgPack or @ref offset is an invalid reading frame.
Result Seek(uint32 offset);
///@{
/// Unpacks the current item as a scalar, type casting if necessary.
///
/// @param [out] pValue Pointer to where to store the data.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pValue cannot represent the current item.
/// Note that loss of information due to type casting will not return an error, but will assert in debug builds.
Result Unpack(bool* pValue) { return UnpackScalar(pValue); }
Result Unpack(char* pValue) { return UnpackScalar(pValue); }
Result Unpack(uint8* pValue) { return UnpackScalar(pValue); }
Result Unpack(uint16* pValue) { return UnpackScalar(pValue); }
Result Unpack(uint32* pValue) { return UnpackScalar(pValue); }
Result Unpack(uint64* pValue) { return UnpackScalar(pValue); }
Result Unpack(int8* pValue) { return UnpackScalar(pValue); }
Result Unpack(int16* pValue) { return UnpackScalar(pValue); }
Result Unpack(int32* pValue) { return UnpackScalar(pValue); }
Result Unpack(int64* pValue) { return UnpackScalar(pValue); }
Result Unpack(float* pValue) { return UnpackScalar(pValue); }
Result Unpack(double* pValue) { return UnpackScalar(pValue); }
///@}
/// Unpacks the current item as a string, copying the data into the specified string buffer. NIL is treated as
/// the empty string.
///
/// @param [out] pString Pointer to the beginning of where to store the string data in.
/// @param [in] sizeInBytes How large the storage buffer is.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pString cannot represent the current item,
/// Eof if unexpected end-of-file was reached.
Result Unpack(char* pString, uint32 sizeInBytes);
/// Unpacks the current item as a string, storing a reference to it in a @ref StringView object. NIL is treated
/// as the empty string.
///
/// The data referenced by the StringView object is only valid as long as the source MsgPack buffer remains
/// valid. It is an error to access the StringView _after_ the MsgPack buffer has been freed.
///
/// @param [out] pStringView Pointer to the StringView object to initialize.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pString cannot represent the current item,
/// Eof if unexpected end-of-file was reached.
Result Unpack(Util::StringView<char>* pStringView);
/// Unpacks the current item as an array of scalars or as binary data, type casting if necessary.
/// NOTE: This will advance the iterator to the last element.
///
/// @param [out] pArray Pointer to the beginning of where to store the data in.
/// @param [in] numElements How many elements wide the storage is.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pArray cannot represent the current item,
/// Eof if unexpected end-of-file was reached.
template <typename T>
Result Unpack(T* pArray, uint32 numElements);
/// Unpacks the current item as a string if @ref T is char, otherwise as an array of scalars or binary data,
/// type casting if necessary.
/// NOTE: This will advance the iterator to the last element.
///
/// @param [out] pArray Pointer to the C-style array to store the data in.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pArray cannot represent the current item,
/// Eof if unexpected end-of-file was reached.
template <typename T, size_t N>
Result Unpack(T (*pArray)[N]) { return Unpack(&((*pArray)[0]), static_cast<uint32>(N)); }
/// Unpacks the current array item as a Vector of scalars, type casting if necessary.
/// NOTE: This will advance the iterator to the last element.
///
/// @param [out] pVector Pointer to the Vector to store the data in.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pVector cannot represent the current item,
/// Eof if unexpected end-of-file was reached.
template <typename T, uint32 DefaultCapacity, typename Allocator>
Result Unpack(Vector<T, DefaultCapacity, Allocator>* pVector);
/// Unpacks the current map item as a SparseVector of scalars, type casting if necessary.
/// NOTE: This will advance the iterator to the last element.
///
/// @param [out] pSparseVector Pointer to the SparseVector to store the data in.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pSparseVector cannot represent the current item,
/// Eof if unexpected end-of-file was reached.
template <typename T, typename CapacityType, CapacityType DefaultCapacity, typename Allocator, uint32... KeyRanges>
Result Unpack(SparseVector<T, CapacityType, DefaultCapacity, Allocator, KeyRanges...>* pSparseVector);
/// Unpacks the current map item as a HashMap of scalars, type casting if necessary.
/// NOTE: This will advance the iterator to the last element.
///
/// @param [out] pMap Pointer to the HashMap to store the data in.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pMap cannot represent the current item,
/// Eof if unexpected end-of-file was reached.
template <typename Key,
typename Value,
typename Allocator,
template<typename> class HashFunc,
template<typename> class EqualFunc,
typename AllocFunc,
size_t GroupSize>
Result Unpack(HashMap<Key, Value, Allocator, HashFunc, EqualFunc, AllocFunc, GroupSize>* pMap);
/// Unpacks the current item as a binary blob.
///
/// @param [out] ppData Pointer to where to store the pointer to the binary data.
/// @param [out] pSizeInBytes Pointer to where to store the size in bytes of the data.
///
/// @returns Result if successful, ErrorInvalidValue if the current item is not a binary blob,
/// Eof if unexpected end-of-file was reached.
Result Unpack(const void** ppData, uint32* pSizeInBytes);
/// Unpacks the current item as a binary blob, copying the data to the given destination.
///
/// @param [out] pDst Pointer to the memory to copy the binary data to.
/// @param [in] sizeInBytes Size in bytes of the buffer represented by @ref pDst.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pDst cannot represent the current item,
/// Eof if unexpected end-of-file was reached.
Result Unpack(void* pDst, uint32 sizeInBytes);
/// Unpacks the current item as a binary encoding of T.
///
/// @param [out] pDst Pointer to the variable or object to copy the binary data to.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pDst cannot represent the current item,
/// Eof if unexpected end-of-file was reached.
template <typename T>
Result UnpackBinary(T* pDst) { return Unpack(static_cast<void*>(pDst), static_cast<uint32>(sizeof(T))); }
/// Convenience function that combines Next() and Unpack(), which advances the reader to the next item token, and
/// unpacks it into the given destination.
///
/// @param [out] pDst Pointer to where to store the data.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pDst cannot represent the current item,
/// Eof if unexpected end-of-file was reached.
template <typename T>
Result UnpackNext(T* pDst);
/// Convenience function that combines Next() and Unpack() twice, which unpacks the next pair of items to their
/// respective given destinations. Useful for manually unpacking a map.
///
/// @param [out] pFirst Pointer to where to store the first element.
/// @param [out] pSecond Pointer to where to store the second element.
///
/// @returns Result if successful, ErrorInvalidValue if @ref pDst cannot represent the current item,
/// Eof if unexpected end-of-file was reached.
template <typename T1, typename T2>
Result UnpackNextPair(T1* pFirst, T2* pSecond);
/// Get the status of the reader.
///
/// @returns Success if no errors have been encountered, Eof if end of buffer has been reached,
/// ErrorInvalidValue if input was malformed, ErrorUnknown otherwise.
Result GetStatus() const { return TranslateCwpReturnCode(m_context.return_code); }
private:
template <typename T>
Result UnpackScalar(T* pValue);
cw_unpack_context m_context;
};
} // Util