1 /***********************************************************************************************************************************
2 Pack Type
3 
4 The pack type encodes binary data compactly while still maintaining structure and strict typing. The idea is based on Thrift,
5 ProtocolBuffers, and Avro, compared here: https://medium.com/better-programming/use-binary-encoding-instead-of-json-dec745ec09b6.
6 The pack type has been further optimized to balance between purely in-memory structures and those intended to be passed via a
7 protocol or saved in a file.
8 
9 Integers are stored with base-128 varint encoding which is equivalent to network byte order, i.e., the endianness of the sending and
10 receiving host don't matter.
11 
12 The overall idea is similar to JSON but IDs are used instead of names, typing is more granular, and the representation is far more
13 compact. A pack can readily be converted to JSON but the reverse is not as precise due to loose typing in JSON. A pack is a stream
14 format, i.e. it is intended to be read in order from beginning to end.
15 
16 Fields in a pack are identified by IDs. A field ID is stored as a delta from the previous ID, which is very efficient, but means
17 that reading from the middle is generally not practical. The size of the gap between field IDs is important -- a gap of 1 never
18 incurs extra cost, but depending on the field type larger gaps may require additional bytes to store the field ID delta.
19 
20 The standard default is the C default for that type (e.g. bool = false, int = 0) but can be changed with the .defaultValue
21 parameter. For example, pckWriteBoolP(write, false, .defaultWrite = true) will write a 0 (i.e. false) with a field ID into the pack,
22 but pckWriteBoolP(write, false) will not write to the pack, it will simply skip the ID.  Note that
23 pckWriteStrP(packWrite, NULL, .defaultWrite = true) is not valid since there is no way to explicitly write a NULL.
24 
25 NULLs are not stored in a pack and are therefore not typed. A NULL is essentially just a gap in the field IDs. Fields that are
26 frequently NULL are best stored at the end of an object. When using read functions the default will always be returned
27 when the field is NULL (i.e. missing). There are times when NULL must be explicitly passed, for example:
28 pckWriteStrP(resultPack, result.pageChecksumResult != NULL ? jsonFromKv(result.pageChecksumResult) : NULL);
29 In this case, NULL is declared since jsonFromKv() does not accept a NULL parameter and, following the rules for NULLs the field ID
30 is skipped when result.pageChecksumResult == NULL. Upon reading, we can declare a NULL_STR when a NULL (field ID gap) is
31 encountered, e.g. jsonToVar(pckReadStrP(jobResult, .defaultValue = NULL_STR)).
32 
33 A pack is an object by default. Objects can store fields, objects, or arrays. Objects and arrays will be referred to collectively as
34 containers. Fields contain data to be stored, e.g. integers, strings, etc.
35 
36 Here is a simple example of a pack:
37 
38 PackWrite *write = pckWriteNew(buffer);
39 pckWriteU64P(write, 77);
40 pckWriteBoolP(write, false, .defaultWrite = true);
41 pckWriteI32P(write, -1, .defaultValue = -1);
42 pckWriteStringP(write, STRDEF("sample"));
43 pckWriteEndP();
44 
45 A string representation of this pack is `1:uint64:77,2:bool:false,4:str:sample`. The boolean was stored even though it was the
46 default because a write was explicitly requested. The int32 field was not stored because the value matched the explicitly set
47 default. Note that there is a gap in the ID stream, which represents the NULL/default value.
48 
49 This pack can be read with:
50 
51 PackRead *read = pckReadNew(buffer);
52 pckReadU64P(read);
53 pckReadBoolP(read);
54 pckReadI32P(read, .defaultValue = -1);
55 pckReadStringP(read);
56 pckReadEndP();
57 
58 Note that defaults are not stored in the pack so any defaults that were applied when writing (by setting .defaultValue) must be
59 applied again when reading by setting .defaultValue if the default value is not a standard C default.
60 
61 If we don't care about the NULL/default, another way to read is:
62 
63 PackRead *read = pckReadNew(buffer);
64 pckReadU64P(read);
65 pckReadBoolP(read);
66 pckReadStringP(read, .id = 4);
67 pckReadEndP();
68 
69 By default each read/write advances the field ID by one. If an ID is specified it must be unique and increasing, because it will
70 advance the field ID beyond the value specified. An error will occur if an ID is attempted to be read/written but the field ID has
71 advanced beyond it.
72 
73 An array can be read with:
74 
75 pckReadArrayBeginP(read);
76 
77 while (pckReadNext(read))
78 {
79     // Read array element
80 }
81 
82 pckReadArrayEndP(read);
83 
84 Note that any container (i.e. array or object) resets the field ID to one so there is no need for the caller to maintain a
85 cumulative field ID. At the end of a container the numbering will continue from wherever the outer container left off.
86 ***********************************************************************************************************************************/
87 #ifndef COMMON_TYPE_PACK_H
88 #define COMMON_TYPE_PACK_H
89 
90 #include <sys/stat.h>
91 #include <time.h>
92 
93 /***********************************************************************************************************************************
94 Minimum number of extra bytes to allocate for packs that are growing or are likely to grow
95 ***********************************************************************************************************************************/
96 #ifndef PACK_EXTRA_MIN
97     #define PACK_EXTRA_MIN                                          128
98 #endif
99 
100 /***********************************************************************************************************************************
101 Object types
102 ***********************************************************************************************************************************/
103 typedef struct PackRead PackRead;
104 typedef struct PackWrite PackWrite;
105 
106 #include "common/io/read.h"
107 #include "common/io/write.h"
108 #include "common/type/object.h"
109 #include "common/type/stringId.h"
110 
111 /***********************************************************************************************************************************
112 Pack data type
113 ***********************************************************************************************************************************/
114 typedef enum
115 {
116     pckTypeArray = STRID5("array", 0x190ca410),
117     pckTypeBin = STRID5("bin", 0x39220),
118     pckTypeBool = STRID5("bool", 0x63de20),
119     pckTypeI32 = STRID6("i32", 0x1e7c91),
120     pckTypeI64 = STRID6("i64", 0x208891),
121     pckTypeObj = STRID5("obj", 0x284f0),
122     pckTypeMode = STRID5("mode", 0x291ed0),
123     pckTypePack = STRID5("pack", 0x58c300),
124     pckTypePtr = STRID5("ptr", 0x4a900),
125     pckTypeStr = STRID5("str", 0x4a930),
126     pckTypeStrId = STRID5("strid", 0x44ca930),
127     pckTypeTime = STRID5("time", 0x2b5340),
128     pckTypeU32 = STRID6("u32", 0x1e7d51),
129     pckTypeU64 = STRID6("u64", 0x208951),
130 } PackType;
131 
132 /***********************************************************************************************************************************
133 Read Constructors
134 ***********************************************************************************************************************************/
135 PackRead *pckReadNew(IoRead *read);
136 
137 // Note that the buffer is not moved into the PackRead mem context and must be moved explicitly if the PackRead object is moved.
138 PackRead *pckReadNewBuf(const Buffer *buffer);
139 
140 /***********************************************************************************************************************************
141 Read Functions
142 ***********************************************************************************************************************************/
143 typedef struct PackIdParam
144 {
145     VAR_PARAM_HEADER;
146     unsigned int id;
147 } PackIdParam;
148 
149 // Read next field. This is useful when the type of the next field is unknown, i.e. a completely dynamic data structure, or for
150 // debugging. If you just need to know if the field exists or not, then use pckReadNullP().
151 bool pckReadNext(PackRead *this);
152 
153 // Current field id. Set after a call to pckReadNext().
154 unsigned int pckReadId(PackRead *this);
155 
156 // Current field type. Set after a call to pckReadNext().
157 PackType pckReadType(PackRead *this);
158 
159 // Is the field NULL? If the field is NULL the id will be advanced so the field does not need to be read explictly. If the field is
160 // not NULL then the id is not advanced since a subsequent read is expected.
161 #define pckReadNullP(this, ...)                                                                                                    \
162     pckReadNull(this, (PackIdParam){VAR_PARAM_INIT, __VA_ARGS__})
163 
164 bool pckReadNull(PackRead *this, PackIdParam param);
165 
166 // Read array begin/end
167 #define pckReadArrayBeginP(this, ...)                                                                                              \
168     pckReadArrayBegin(this, (PackIdParam){VAR_PARAM_INIT, __VA_ARGS__})
169 
170 void pckReadArrayBegin(PackRead *this, PackIdParam param);
171 
172 #define pckReadArrayEndP(this)                                                                                                     \
173     pckReadArrayEnd(this)
174 
175 void pckReadArrayEnd(PackRead *this);
176 
177 // Read binary
178 typedef struct PckReadBinParam
179 {
180     VAR_PARAM_HEADER;
181     unsigned int id;
182 } PckReadBinParam;
183 
184 #define pckReadBinP(this, ...)                                                                                                     \
185     pckReadBin(this, (PckReadBinParam){VAR_PARAM_INIT, __VA_ARGS__})
186 
187 Buffer *pckReadBin(PackRead *this, PckReadBinParam param);
188 
189 // Read boolean
190 typedef struct PckReadBoolParam
191 {
192     VAR_PARAM_HEADER;
193     unsigned int id;
194     uint32_t defaultValue;
195 } PckReadBoolParam;
196 
197 #define pckReadBoolP(this, ...)                                                                                                    \
198     pckReadBool(this, (PckReadBoolParam){VAR_PARAM_INIT, __VA_ARGS__})
199 
200 bool pckReadBool(PackRead *this, PckReadBoolParam param);
201 
202 // Read 32-bit signed integer
203 typedef struct PckReadI32Param
204 {
205     VAR_PARAM_HEADER;
206     unsigned int id;
207     int32_t defaultValue;
208 } PckReadI32Param;
209 
210 #define pckReadI32P(this, ...)                                                                                                     \
211     pckReadI32(this, (PckReadI32Param){VAR_PARAM_INIT, __VA_ARGS__})
212 
213 int32_t pckReadI32(PackRead *this, PckReadI32Param param);
214 
215 // Read 64-bit signed integer
216 typedef struct PckReadI64Param
217 {
218     VAR_PARAM_HEADER;
219     unsigned int id;
220     int64_t defaultValue;
221 } PckReadI64Param;
222 
223 #define pckReadI64P(this, ...)                                                                                                     \
224     pckReadI64(this, (PckReadI64Param){VAR_PARAM_INIT, __VA_ARGS__})
225 
226 int64_t pckReadI64(PackRead *this, PckReadI64Param param);
227 
228 // Read mode
229 typedef struct PckReadModeParam
230 {
231     VAR_PARAM_HEADER;
232     unsigned int id;
233     mode_t defaultValue;
234 } PckReadModeParam;
235 
236 #define pckReadModeP(this, ...)                                                                                                     \
237     pckReadMode(this, (PckReadModeParam){VAR_PARAM_INIT, __VA_ARGS__})
238 
239 mode_t pckReadMode(PackRead *this, PckReadModeParam param);
240 
241 // Move to a new parent mem context
242 __attribute__((always_inline)) static inline PackRead *
pckReadMove(PackRead * const this,MemContext * const parentNew)243 pckReadMove(PackRead *const this, MemContext *const parentNew)
244 {
245     return objMove(this, parentNew);
246 }
247 
248 // Read object begin/end
249 #define pckReadObjBeginP(this, ...)                                                                                                \
250     pckReadObjBegin(this, (PackIdParam){VAR_PARAM_INIT, __VA_ARGS__})
251 
252 void pckReadObjBegin(PackRead *this, PackIdParam param);
253 
254 #define pckReadObjEndP(this)                                                                                                       \
255     pckReadObjEnd(this)
256 
257 void pckReadObjEnd(PackRead *this);
258 
259 // Read pack
260 typedef struct PckReadPackParam
261 {
262     VAR_PARAM_HEADER;
263     unsigned int id;
264 } PckReadPackParam;
265 
266 #define pckReadPackP(this, ...)                                                                                                    \
267     pckReadPack(this, (PckReadPackParam){VAR_PARAM_INIT, __VA_ARGS__})
268 
269 PackRead *pckReadPack(PackRead *this, PckReadPackParam param);
270 
271 // Read pack buffer
272 #define pckReadPackBufP(this, ...)                                                                                                 \
273     pckReadPackBuf(this, (PckReadPackParam){VAR_PARAM_INIT, __VA_ARGS__})
274 
275 Buffer *pckReadPackBuf(PackRead *this, PckReadPackParam param);
276 
277 // Read pointer. Use with extreme caution. Pointers cannot be sent to another host -- they must only be used locally.
278 typedef struct PckReadPtrParam
279 {
280     VAR_PARAM_HEADER;
281     unsigned int id;
282 } PckReadPtrParam;
283 
284 #define pckReadPtrP(this, ...)                                                                                                     \
285     pckReadPtr(this, (PckReadPtrParam){VAR_PARAM_INIT, __VA_ARGS__})
286 
287 void *pckReadPtr(PackRead *this, PckReadPtrParam param);
288 
289 // Read string
290 typedef struct PckReadStrParam
291 {
292     VAR_PARAM_HEADER;
293     unsigned int id;
294     const String *defaultValue;
295 } PckReadStrParam;
296 
297 #define pckReadStrP(this, ...)                                                                                                     \
298     pckReadStr(this, (PckReadStrParam){VAR_PARAM_INIT, __VA_ARGS__})
299 
300 String *pckReadStr(PackRead *this, PckReadStrParam param);
301 
302 // Read string id
303 typedef struct PckReadStrIdParam
304 {
305     VAR_PARAM_HEADER;
306     unsigned int id;
307     StringId defaultValue;
308 } PckReadStrIdParam;
309 
310 #define pckReadStrIdP(this, ...)                                                                                                   \
311     pckReadStrId(this, (PckReadStrIdParam){VAR_PARAM_INIT, __VA_ARGS__})
312 
313 uint64_t pckReadStrId(PackRead *this, PckReadStrIdParam param);
314 
315 // Read string list
316 typedef struct PckReadStrLstParam
317 {
318     VAR_PARAM_HEADER;
319     unsigned int id;
320 } PckReadStrLstParam;
321 
322 #define pckReadStrLstP(this, ...)                                                                                                  \
323     pckReadStrLst(this, (PckReadStrLstParam){VAR_PARAM_INIT, __VA_ARGS__})
324 
325 StringList *pckReadStrLst(PackRead *const this, PckReadStrLstParam param);
326 
327 // Read time
328 typedef struct PckReadTimeParam
329 {
330     VAR_PARAM_HEADER;
331     unsigned int id;
332     time_t defaultValue;
333 } PckReadTimeParam;
334 
335 #define pckReadTimeP(this, ...)                                                                                                    \
336     pckReadTime(this, (PckReadTimeParam){VAR_PARAM_INIT, __VA_ARGS__})
337 
338 time_t pckReadTime(PackRead *this, PckReadTimeParam param);
339 
340 // Read 32-bit unsigned integer
341 typedef struct PckReadU32Param
342 {
343     VAR_PARAM_HEADER;
344     unsigned int id;
345     uint32_t defaultValue;
346 } PckReadU32Param;
347 
348 #define pckReadU32P(this, ...)                                                                                                     \
349     pckReadU32(this, (PckReadU32Param){VAR_PARAM_INIT, __VA_ARGS__})
350 
351 uint32_t pckReadU32(PackRead *this, PckReadU32Param param);
352 
353 // Read 64-bit unsigned integer
354 typedef struct PckReadU64Param
355 {
356     VAR_PARAM_HEADER;
357     unsigned int id;
358     uint64_t defaultValue;
359 } PckReadU64Param;
360 
361 #define pckReadU64P(this, ...)                                                                                                     \
362     pckReadU64(this, (PckReadU64Param){VAR_PARAM_INIT, __VA_ARGS__})
363 
364 uint64_t pckReadU64(PackRead *this, PckReadU64Param param);
365 
366 // Read end
367 #define pckReadEndP(this)                                                                                                          \
368     pckReadEnd(this)
369 
370 void pckReadEnd(PackRead *this);
371 
372 /***********************************************************************************************************************************
373 Read Destructor
374 ***********************************************************************************************************************************/
375 __attribute__((always_inline)) static inline void
pckReadFree(PackRead * const this)376 pckReadFree(PackRead *const this)
377 {
378     objFree(this);
379 }
380 
381 /***********************************************************************************************************************************
382 Write Constructors
383 ***********************************************************************************************************************************/
384 PackWrite *pckWriteNew(IoWrite *write);
385 
386 // Note that the buffer is not moved into the PackWrite mem context and must be moved explicitly if the PackWrite object is moved.
387 PackWrite *pckWriteNewBuf(Buffer *buffer);
388 
389 /***********************************************************************************************************************************
390 Write Functions
391 ***********************************************************************************************************************************/
392 // Write array begin/end
393 #define pckWriteArrayBeginP(this, ...)                                                                                             \
394     pckWriteArrayBegin(this, (PackIdParam){VAR_PARAM_INIT, __VA_ARGS__})
395 
396 PackWrite *pckWriteArrayBegin(PackWrite *this, PackIdParam param);
397 
398 #define pckWriteArrayEndP(this)                                                                                                    \
399     pckWriteArrayEnd(this)
400 
401 PackWrite *pckWriteArrayEnd(PackWrite *this);
402 
403 // Write binary
404 typedef struct PckWriteBinParam
405 {
406     VAR_PARAM_HEADER;
407     unsigned int id;
408 } PckWriteBinParam;
409 
410 #define pckWriteBinP(this, value, ...)                                                                                             \
411     pckWriteBin(this, value, (PckWriteBinParam){VAR_PARAM_INIT, __VA_ARGS__})
412 
413 PackWrite *pckWriteBin(PackWrite *this, const Buffer *value, PckWriteBinParam param);
414 
415 // Write boolean
416 typedef struct PckWriteBoolParam
417 {
418     VAR_PARAM_HEADER;
419     bool defaultWrite;
420     unsigned int id;
421     uint32_t defaultValue;
422 } PckWriteBoolParam;
423 
424 #define pckWriteBoolP(this, value, ...)                                                                                            \
425     pckWriteBool(this, value, (PckWriteBoolParam){VAR_PARAM_INIT, __VA_ARGS__})
426 
427 PackWrite *pckWriteBool(PackWrite *this, bool value, PckWriteBoolParam param);
428 
429 // Write 32-bit signed integer
430 typedef struct PckWriteI32Param
431 {
432     VAR_PARAM_HEADER;
433     bool defaultWrite;
434     unsigned int id;
435     int32_t defaultValue;
436 } PckWriteI32Param;
437 
438 #define pckWriteI32P(this, value, ...)                                                                                             \
439     pckWriteI32(this, value, (PckWriteI32Param){VAR_PARAM_INIT, __VA_ARGS__})
440 
441 PackWrite *pckWriteI32(PackWrite *this, int32_t value, PckWriteI32Param param);
442 
443 // Write 64-bit signed integer
444 typedef struct PckWriteI64Param
445 {
446     VAR_PARAM_HEADER;
447     bool defaultWrite;
448     unsigned int id;
449     int64_t defaultValue;
450 } PckWriteI64Param;
451 
452 #define pckWriteI64P(this, value, ...)                                                                                             \
453     pckWriteI64(this, value, (PckWriteI64Param){VAR_PARAM_INIT, __VA_ARGS__})
454 
455 PackWrite *pckWriteI64(PackWrite *this, int64_t value, PckWriteI64Param param);
456 
457 // Write mode
458 typedef struct PckWriteModeParam
459 {
460     VAR_PARAM_HEADER;
461     bool defaultWrite;
462     unsigned int id;
463     mode_t defaultValue;
464 } PckWriteModeParam;
465 
466 #define pckWriteModeP(this, value, ...)                                                                                             \
467     pckWriteMode(this, value, (PckWriteModeParam){VAR_PARAM_INIT, __VA_ARGS__})
468 
469 PackWrite *pckWriteMode(PackWrite *this, mode_t value, PckWriteModeParam param);
470 
471 // Move to a new parent mem context
472 __attribute__((always_inline)) static inline PackWrite *
pckWriteMove(PackWrite * const this,MemContext * const parentNew)473 pckWriteMove(PackWrite *const this, MemContext *const parentNew)
474 {
475     return objMove(this, parentNew);
476 }
477 
478 // Write null
479 #define pckWriteNullP(this)                                                                                                        \
480     pckWriteNull(this)
481 
482 PackWrite *pckWriteNull(PackWrite *this);
483 
484 // Write object begin/end
485 #define pckWriteObjBeginP(this, ...)                                                                                               \
486     pckWriteObjBegin(this, (PackIdParam){VAR_PARAM_INIT, __VA_ARGS__})
487 
488 PackWrite *pckWriteObjBegin(PackWrite *this, PackIdParam param);
489 
490 #define pckWriteObjEndP(this)                                                                                                      \
491     pckWriteObjEnd(this)
492 
493 PackWrite *pckWriteObjEnd(PackWrite *this);
494 
495 // Write pack
496 typedef struct PckWritePackParam
497 {
498     VAR_PARAM_HEADER;
499     bool defaultWrite;
500     unsigned int id;
501 } PckWritePackParam;
502 
503 #define pckWritePackP(this, value, ...)                                                                                            \
504     pckWritePack(this, value, (PckWritePackParam){VAR_PARAM_INIT, __VA_ARGS__})
505 
506 PackWrite *pckWritePack(PackWrite *this, const PackWrite *value, PckWritePackParam param);
507 
508 // Write pointer. Use with extreme caution. Pointers cannot be sent to another host -- they must only be used locally.
509 typedef struct PckWritePtrParam
510 {
511     VAR_PARAM_HEADER;
512     bool defaultWrite;
513     unsigned int id;
514 } PckWritePtrParam;
515 
516 #define pckWritePtrP(this, value, ...)                                                                                             \
517     pckWritePtr(this, value, (PckWritePtrParam){VAR_PARAM_INIT, __VA_ARGS__})
518 
519 PackWrite *pckWritePtr(PackWrite *this, const void *value, PckWritePtrParam param);
520 
521 // Write string
522 typedef struct PckWriteStrParam
523 {
524     VAR_PARAM_HEADER;
525     bool defaultWrite;
526     unsigned int id;
527     const String *defaultValue;
528 } PckWriteStrParam;
529 
530 #define pckWriteStrP(this, value, ...)                                                                                             \
531     pckWriteStr(this, value, (PckWriteStrParam){VAR_PARAM_INIT, __VA_ARGS__})
532 
533 PackWrite *pckWriteStr(PackWrite *this, const String *value, PckWriteStrParam param);
534 
535 // Write string id
536 typedef struct PckWriteStrIdParam
537 {
538     VAR_PARAM_HEADER;
539     bool defaultWrite;
540     unsigned int id;
541     StringId defaultValue;
542 } PckWriteStrIdParam;
543 
544 #define pckWriteStrIdP(this, value, ...)                                                                                           \
545     pckWriteStrId(this, value, (PckWriteStrIdParam){VAR_PARAM_INIT, __VA_ARGS__})
546 
547 PackWrite *pckWriteStrId(PackWrite *this, uint64_t value, PckWriteStrIdParam param);
548 
549 // Write string list
550 typedef struct PckWriteStrLstParam
551 {
552     VAR_PARAM_HEADER;
553     unsigned int id;
554 } PckWriteStrLstParam;
555 
556 #define pckWriteStrLstP(this, value, ...)                                                                                          \
557     pckWriteStrLst(this, value, (PckWriteStrLstParam){VAR_PARAM_INIT, __VA_ARGS__})
558 
559 PackWrite *pckWriteStrLst(PackWrite *const this, const StringList *const value, const PckWriteStrLstParam param);
560 
561 // Write time
562 typedef struct PckWriteTimeParam
563 {
564     VAR_PARAM_HEADER;
565     bool defaultWrite;
566     unsigned int id;
567     time_t defaultValue;
568 } PckWriteTimeParam;
569 
570 #define pckWriteTimeP(this, value, ...)                                                                                            \
571     pckWriteTime(this, value, (PckWriteTimeParam){VAR_PARAM_INIT, __VA_ARGS__})
572 
573 PackWrite *pckWriteTime(PackWrite *this, time_t value, PckWriteTimeParam param);
574 
575 // Write 32-bit unsigned integer
576 typedef struct PckWriteU32Param
577 {
578     VAR_PARAM_HEADER;
579     bool defaultWrite;
580     unsigned int id;
581     uint32_t defaultValue;
582 } PckWriteU32Param;
583 
584 #define pckWriteU32P(this, value, ...)                                                                                             \
585     pckWriteU32(this, value, (PckWriteU32Param){VAR_PARAM_INIT, __VA_ARGS__})
586 
587 PackWrite *pckWriteU32(PackWrite *this, uint32_t value, PckWriteU32Param param);
588 
589 // Write 64-bit unsigned integer
590 typedef struct PckWriteU64Param
591 {
592     VAR_PARAM_HEADER;
593     bool defaultWrite;
594     unsigned int id;
595     uint64_t defaultValue;
596 } PckWriteU64Param;
597 
598 #define pckWriteU64P(this, value, ...)                                                                                             \
599     pckWriteU64(this, value, (PckWriteU64Param){VAR_PARAM_INIT, __VA_ARGS__})
600 
601 PackWrite *pckWriteU64(PackWrite *this, uint64_t value, PckWriteU64Param param);
602 
603 // Write end
604 #define pckWriteEndP(this)                                                                                                         \
605     pckWriteEnd(this)
606 
607 PackWrite *pckWriteEnd(PackWrite *this);
608 
609 /***********************************************************************************************************************************
610 Write Getters/Setters
611 ***********************************************************************************************************************************/
612 // Get buffer the pack is writing to (returns NULL if pckWriteNewBuf() was not used to construct the object). This function is only
613 // valid after pckWriteEndP() has been called.
614 const Buffer *pckWriteBuf(const PackWrite *this);
615 
616 /***********************************************************************************************************************************
617 Write Destructor
618 ***********************************************************************************************************************************/
619 __attribute__((always_inline)) static inline void
pckWriteFree(PackWrite * const this)620 pckWriteFree(PackWrite *const this)
621 {
622     objFree(this);
623 }
624 
625 /***********************************************************************************************************************************
626 Macros for function logging
627 ***********************************************************************************************************************************/
628 String *pckReadToLog(const PackRead *this);
629 
630 #define FUNCTION_LOG_PACK_READ_TYPE                                                                                                \
631     PackRead *
632 #define FUNCTION_LOG_PACK_READ_FORMAT(value, buffer, bufferSize)                                                                   \
633     FUNCTION_LOG_STRING_OBJECT_FORMAT(value, pckReadToLog, buffer, bufferSize)
634 
635 String *pckWriteToLog(const PackWrite *this);
636 
637 #define FUNCTION_LOG_PACK_WRITE_TYPE                                                                                               \
638     PackWrite *
639 #define FUNCTION_LOG_PACK_WRITE_FORMAT(value, buffer, bufferSize)                                                                  \
640     FUNCTION_LOG_STRING_OBJECT_FORMAT(value, pckWriteToLog, buffer, bufferSize)
641 
642 #endif
643