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