netSerial

serializer producing compact bitstreams
git clone https://noulin.net/git/netSerial.git
Log | Files | Refs | README | LICENSE

netSerial.c (145543B)


      1 
      2 #include "libsheepyObject.h"
      3 #include "netSerial.h"
      4 #include "netSerialInternal.h"
      5 
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <stdio.h>
      9 
     10 #define lv logVarG
     11 
     12 void initiateNetSerialLevel0(smallJsont *self);
     13 void initiateNetSerialLevel1(smallJsont *self);
     14 void initiateNetSerialLevel2(smallJsont *self);
     15 void initiateNetSerial(smallJsont *self);
     16 void registerMethodsNetSerialLevel0(smallJsonFunctionst *f);
     17 void registerMethodsNetSerialLevel1(smallJsonFunctionst *f);
     18 void registerMethodsNetSerialLevel2(smallJsonFunctionst *f);
     19 void registerMethodsNetSerial(smallJsonFunctionst *f);
     20 void initiateAllocateNetSerialLevel0(smallJsont **self);
     21 void initiateAllocateNetSerialLevel1(smallJsont **self);
     22 void initiateAllocateNetSerialLevel2(smallJsont **self);
     23 void initiateAllocateNetSerial(smallJsont **self);
     24 void finalizeNetSerial(void);
     25 smallJsont* allocNetSerialLevel0(void);
     26 smallJsont* allocNetSerialLevel1(void);
     27 smallJsont* allocNetSerialLevel2(void);
     28 smallJsont* allocNetSerial(void);
     29 internal const char* helpNetSerial(smallJsont *self);
     30 internal smallBytest* serialNetSerialLevel0(smallJsont *self);
     31 internal smallBytest* serialNetSerialLevel1(smallJsont *self);
     32 internal smallBytest* serialNetSerialLevel2(smallJsont *self);
     33 internal smallBytest* serialNetSerial(smallJsont *self);
     34 internal smallJsont* deserialNetSerialLevel0(smallJsont *self, smallBytest *data);
     35 internal smallJsont* deserialNetSerialLevel1(smallJsont *self, smallBytest *data);
     36 internal smallJsont* deserialNetSerialLevel2(smallJsont *self, smallBytest *data);
     37 internal smallJsont* deserialNetSerial(smallJsont *self, smallBytest *data);
     38 
     39 internal void uintToNetTypeVarint(sBytest **buf, u8 type, u64 value);
     40 internal void uintToVarint(sBytest **buf, u64 value);
     41 internal u64 netTypeVarintToUint(u8 **buf);
     42 internal u64 varintToUint(u8 **buf);
     43 
     44 internal sBytest* netSerialLevel0(smallt *o);
     45 internal void dictNetSerialLevel0(sBytest **r, sDictt *dict);
     46 internal void arrayNetSerialLevel0(sBytest **r, sArrayt *array);
     47 internal sBytest* netSerialLevel1(smallt *o);
     48 internal void dictNetSerialLevel1(sBytest **r, sDictt *dict, contextt *ctx);
     49 internal void arrayNetSerialLevel1(sBytest **r, sArrayt *array, contextt *ctx);
     50 internal sBytest* netSerialLevel2(smallt *o);
     51 internal void dictNetSerialLevel2(sBytest **r, sDictt *dict, contextt *ctx, bool packed);
     52 internal void arrayNetSerialLevel2(sBytest **r, sArrayt *array, contextt *ctx, bool packed);
     53 internal sBytest* netSerial(smallt *o);
     54 internal void dictNetSerial(sBytest **r, sDictt *dict, contextt *ctx, packingT packing);
     55 internal void arrayNetSerial(sBytest **r, sArrayt *array, contextt *ctx, packingT packing);
     56 
     57 internal smallt* netDeserialLevel0(sBytest *obj);
     58 internal void dictNetDeserialLevel0(sDictt **dict, char **data);
     59 internal void arrayNetDeserialLevel0(sArrayt **array, char **data);
     60 internal smallt* netDeserialLevel1(sBytest *obj);
     61 internal void dictNetDeserialLevel1(sDictt **dict, u8 **data, contextt *ctx);
     62 internal void arrayNetDeserialLevel1(sArrayt **array, u8 **data, contextt *ctx);
     63 internal smallt* netDeserialLevel2(sBytest *obj);
     64 internal void dictNetDeserialLevel2(sDictt **dict, u8 **data, contextt *ctx, bool packed);
     65 internal u8 isDictUniform(sDictt *dict);
     66 internal u8 isArrayUniform(sArrayt *array);
     67 internal void uniformDictNetDeserialLevel2(sDictt **dict, u8 **data, contextt *ctx, bool packed);
     68 internal void arrayNetDeserialLevel2(sArrayt **array, u8 **data, contextt *ctx, bool packed);
     69 internal void uniformArrayNetDeserialLevel2(sArrayt **array, u8 **data, contextt *ctx, bool packed);
     70 internal smallt* netDeserial(sBytest *obj);
     71 internal void dictNetDeserial(sDictt **dict, u8 **data, contextt *ctx, bool packed);
     72 internal void uniformDictNetDeserial(sDictt **dict, u8 **data, contextt *ctx, bool packed);
     73 internal void arrayNetDeserial(sArrayt **array, u8 **data, contextt *ctx, bool packed);
     74 internal void uniformArrayNetDeserial(sArrayt **array, u8 **data, contextt *ctx, bool packed);
     75 
     76 /* enable/disable logging */
     77 /* #undef pLog */
     78 /* #define pLog(...) */
     79 
     80 void initiateNetSerialLevel0(smallJsont *self) {
     81 
     82   initiateSmallJson(self);
     83 
     84   self->type = "netSerial";
     85   if (!netSerialF) {
     86     netSerialF            = malloc(sizeof(smallJsonFunctionst));
     87     registerMethodsNetSerialLevel0(netSerialF);
     88     pErrorNot0(atexit(finalizeNetSerial));
     89   }
     90   self->f = netSerialF;
     91 }
     92 
     93 void initiateNetSerialLevel1(smallJsont *self) {
     94 
     95   initiateSmallJson(self);
     96 
     97   self->type = "netSerial";
     98   if (!netSerialF) {
     99     netSerialF            = malloc(sizeof(smallJsonFunctionst));
    100     registerMethodsNetSerialLevel1(netSerialF);
    101     pErrorNot0(atexit(finalizeNetSerial));
    102   }
    103   self->f = netSerialF;
    104 }
    105 
    106 void initiateNetSerialLevel2(smallJsont *self) {
    107 
    108   initiateSmallJson(self);
    109 
    110   self->type = "netSerial";
    111   if (!netSerialF) {
    112     netSerialF            = malloc(sizeof(smallJsonFunctionst));
    113     registerMethodsNetSerialLevel2(netSerialF);
    114     pErrorNot0(atexit(finalizeNetSerial));
    115   }
    116   self->f = netSerialF;
    117 }
    118 
    119 void initiateNetSerial(smallJsont *self) {
    120 
    121   initiateSmallJson(self);
    122 
    123   self->type = "netSerial";
    124   if (!netSerialF) {
    125     netSerialF            = malloc(sizeof(smallJsonFunctionst));
    126     registerMethodsNetSerial(netSerialF);
    127     pErrorNot0(atexit(finalizeNetSerial));
    128   }
    129   self->f = netSerialF;
    130 }
    131 
    132 void registerMethodsNetSerialLevel0(smallJsonFunctionst *f) {
    133 
    134   registerMethodsSmallJson(f);
    135   f->help      = helpNetSerial;
    136   f->serial    = serialNetSerialLevel0;
    137   f->deserial  = deserialNetSerialLevel0;
    138 }
    139 
    140 void registerMethodsNetSerialLevel1(smallJsonFunctionst *f) {
    141 
    142   registerMethodsSmallJson(f);
    143   f->help      = helpNetSerial;
    144   f->serial    = serialNetSerialLevel1;
    145   f->deserial  = deserialNetSerialLevel1;
    146 }
    147 
    148 void registerMethodsNetSerialLevel2(smallJsonFunctionst *f) {
    149 
    150   registerMethodsSmallJson(f);
    151   f->help      = helpNetSerial;
    152   f->serial    = serialNetSerialLevel2;
    153   f->deserial  = deserialNetSerialLevel2;
    154 }
    155 
    156 void registerMethodsNetSerial(smallJsonFunctionst *f) {
    157 
    158   registerMethodsSmallJson(f);
    159   f->help      = helpNetSerial;
    160   f->serial    = serialNetSerial;
    161   f->deserial  = deserialNetSerial;
    162 }
    163 
    164 void initiateAllocateNetSerialLevel0(smallJsont **self) {
    165 
    166   if (self) {
    167     initiateG(self); // call initiateAllocateSmallJson to initialize the container recycling system
    168     if (*self) {
    169       initiateNetSerialLevel0(*self);
    170     }
    171   }
    172 }
    173 
    174 void initiateAllocateNetSerialLevel1(smallJsont **self) {
    175 
    176   if (self) {
    177     initiateG(self); // call initiateAllocateSmallJson to initialize the container recycling system
    178     if (*self) {
    179       initiateNetSerialLevel1(*self);
    180     }
    181   }
    182 }
    183 
    184 void initiateAllocateNetSerialLevel2(smallJsont **self) {
    185 
    186   if (self) {
    187     initiateG(self); // call initiateAllocateSmallJson to initialize the container recycling system
    188     if (*self) {
    189       initiateNetSerialLevel2(*self);
    190     }
    191   }
    192 }
    193 
    194 void initiateAllocateNetSerial(smallJsont **self) {
    195 
    196   if (self) {
    197     initiateG(self); // call initiateAllocateSmallJson to initialize the container recycling system
    198     if (*self) {
    199       initiateNetSerial(*self);
    200     }
    201   }
    202 }
    203 
    204 void finalizeNetSerial(void) {
    205 
    206   if (netSerialF) {
    207     free(netSerialF);
    208     netSerialF = NULL;
    209   }
    210 }
    211 
    212 smallJsont* allocNetSerialLevel0(void) {
    213   smallJsont *r = NULL;
    214 
    215   initiateAllocateNetSerialLevel0(&r);
    216   ret r;
    217 }
    218 
    219 smallJsont* allocNetSerialLevel1(void) {
    220   smallJsont *r = NULL;
    221 
    222   initiateAllocateNetSerialLevel1(&r);
    223   ret r;
    224 }
    225 
    226 smallJsont* allocNetSerialLevel2(void) {
    227   smallJsont *r = NULL;
    228 
    229   initiateAllocateNetSerialLevel2(&r);
    230   ret r;
    231 }
    232 
    233 smallJsont* allocNetSerial(void) {
    234   smallJsont *r = NULL;
    235 
    236   initiateAllocateNetSerial(&r);
    237   ret r;
    238 }
    239 
    240 
    241 internal const char* helpNetSerial(smallJsont UNUSED *self) {
    242   ret "TODO helpNetSerial \n" helpTextSmallJson;
    243 }
    244 
    245 /**
    246  * encode type in lower nibble, uint value in high nibble and next bytes as varuint
    247  */
    248 internal void uintToNetTypeVarint(sBytest **buf, u8 type, u64 value) {
    249   u64 c = value;
    250   /* encode b0..2 */
    251   u8  b = type + ((c & 0x7) << 4);
    252   if (c & 0xFFFFFFFFFFFFFFF8) {
    253     b |= 0x80;
    254     sBytesPush(buf, b);
    255     c >>=3;
    256     /* encode b3..9 ...*/
    257     while(c) {
    258       b = c & 0x7F;
    259       if (c & 0xFFFFFFFFFFFFFF80)
    260         b |= 0x80;
    261       sBytesPush(buf, b);
    262       c >>=7;
    263     }
    264   }
    265   else
    266     sBytesPush(buf, b);
    267 }
    268 
    269 /**
    270  * encode uint as varuint
    271  */
    272 internal void uintToVarint(sBytest **buf, u64 value) {
    273   u64 c = value;
    274   u8  b = c & 0x7F;
    275   if (c & 0xFFFFFFFFFFFFFF80) {
    276     b |= 0x80;
    277     sBytesPush(buf, b);
    278     c >>=7;
    279     /* encode b7..14 ...*/
    280     while(c) {
    281       b = c & 0x7F;
    282       if (c & 0xFFFFFFFFFFFFFF80)
    283         b |= 0x80;
    284       sBytesPush(buf, b);
    285       c >>=7;
    286     }
    287   }
    288   else
    289     sBytesPush(buf, b);
    290 }
    291 
    292 /**
    293  * decode type and varuint to uint
    294  */
    295 internal u64 netTypeVarintToUint(u8 **buf) {
    296   u64 r = 0;
    297 
    298   r = (**buf >> 4) & 0x7;
    299 
    300   u8 c = 0;
    301   while (**buf & 0x80) {
    302     (*buf)++;
    303     // note: keep 0x7FUL to use 64 bit shift operation, without UL a 32 bit shift operation is use and then casted to 64 bit
    304     r |= (**buf & 0x7FUL) << (7*c+3);
    305     c++;
    306   }
    307   (*buf)++;
    308   ret r;
    309 }
    310 
    311 /**
    312  * decode varuint to uint
    313  */
    314 internal u64 varintToUint(u8 **buf) {
    315   u64 r = 0;
    316 
    317   r = (**buf) & 0x7F;
    318   u8 c = 1;
    319   while (**buf & 0x80) {
    320     (*buf)++;
    321     // note: keep 0x7FUL to use 64 bit shift operation, without UL a 32 bit shift operation is use and then casted to 64 bit
    322     r |= (**buf & 0x7FUL) << (7*c);
    323     c++;
    324   }
    325   (*buf)++;
    326   ret r;
    327 }
    328 
    329 // -------------------------------------
    330 // Serializers
    331 
    332 // level 0
    333 // like smallJson with ints and length encoded as varints
    334 
    335 /**
    336  * serializer top function
    337  */
    338 internal sBytest* netSerialLevel0(smallt *o) {
    339   sBytest *r = NULL;
    340   sBytest *B = NULL;
    341 
    342   switch(o->type) {
    343     case UNDEFINED:
    344       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
    345       break;
    346     case BOOL: {
    347       u8 c = NET_SERIAL_TYPES[(u8)o->type];
    348       // set bit 4 when true
    349       if (((sBoolt *)&(o->type))->value)
    350         c |= (1<<4);
    351       sBytesPush(&r, c);
    352       }
    353       break;
    354     case CONTAINER:
    355       // undefined
    356       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
    357       break;
    358     case DICT:
    359       dictNetSerialLevel0(&r, (sDictt *)&(o->type));
    360       break;
    361     case DOUBLE:
    362       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
    363       sBytesPushBuffer(&r, &((sDoublet *)&(o->type))->value, sizeof(double));
    364       break;
    365     case INT: {
    366       // encode int to varint
    367       // v is int64_t to convert to varint
    368       i64 v = ((sIntt *)&(o->type))->value;
    369       // encode v with arithmetic shifts
    370       uintToNetTypeVarint(&r, NET_SERIAL_TYPES[(u8)o->type], (v << 1) ^ (v >> 63));
    371       }
    372       break;
    373     case STRING:
    374       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
    375       sBytesPushBuffer(&r, &((sStringt *)&(o->type))->data, sizeof(sStringt) + strlen(&(((sStringt *)&(o->type))->data)) -1);
    376       break;
    377     case ARRAY:
    378       arrayNetSerialLevel0(&r, (sArrayt *)&(o->type));
    379       break;
    380     case BYTES:
    381       B = (sBytest *)&(o->type);
    382       uintToNetTypeVarint(&r, NET_SERIAL_TYPES[(u8)o->type], B->count);
    383       sBytesPushBuffer(&r, &(B->data), B->count);
    384       break;
    385   }
    386   ret r;
    387 }
    388 
    389 /**
    390  * serialize dictionary
    391  *
    392  * the serialized dict is pushed to r.
    393  * All elements are serialized recursively
    394  *
    395  * the data in containers is not serialized
    396  *
    397  * \param
    398  *   r small bytes object
    399  *   dict dictionary to serialize
    400  */
    401 internal void dictNetSerialLevel0(sBytest **r, sDictt *dict) {
    402   sBytest *B = NULL;
    403 
    404   uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)dict->type], dict->count);
    405 
    406   forEachSDict(dict, e) {
    407     if (e->key) {
    408       sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
    409 
    410       switch(e->data->type) {
    411         case UNDEFINED:
    412           sBytesPush(r, NET_SERIAL_TYPES[(u8)e->data->type]);
    413           break;
    414         case BOOL: {
    415             u8 c = NET_SERIAL_TYPES[(u8)e->data->type];
    416             // set bit 4 when true
    417             if (((sBoolt *)(e->data))->value)
    418               c |= (1<<4);
    419             sBytesPush(r, c);
    420            }
    421           break;
    422         case CONTAINER:
    423           // undefined
    424           sBytesPush(r, NET_SERIAL_TYPES[(u8)e->data->type]);
    425           break;
    426         case DICT:
    427           dictNetSerialLevel0(r, (sDictt *)(e->data));
    428           break;
    429         case DOUBLE:
    430           sBytesPush(r, NET_SERIAL_TYPES[(u8)e->data->type]);
    431           sBytesPushBuffer(r, &((sDoublet *)(e->data))->value, sizeof(double));
    432           break;
    433         case INT: {
    434             // encode int to varint
    435             // v is int64_t to convert to varint
    436             i64 v = ((sIntt *)(e->data))->value;
    437             // encode v with arithmetic shifts
    438             uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->data->type], (v << 1) ^ (v >> 63));
    439            }
    440           break;
    441         case STRING:
    442           sBytesPush(r, NET_SERIAL_TYPES[(u8)e->data->type]);
    443           sBytesPushBuffer(r, &((sStringt *)(e->data))->data, sizeof(sStringt) + strlen(&(((sStringt *)(e->data))->data)) -1);
    444           break;
    445         case ARRAY:
    446           arrayNetSerialLevel0(r, (sArrayt *)(e->data));
    447           break;
    448         case BYTES:
    449           B = (sBytest *)(e->data);
    450           uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->data->type], B->count);
    451           sBytesPushBuffer(r, &(B->data), B->count);
    452           break;
    453        }
    454      }
    455   }
    456   ret;
    457 }
    458 
    459 /**
    460  * serialize array
    461  *
    462  * the serialized array is pushed to r.
    463  * All elements are serialized recursively
    464  *
    465  * the data in containers is not serialized
    466  *
    467  * \param
    468  *   r small bytes object
    469  *   array to serialize
    470  */
    471 internal void arrayNetSerialLevel0(sBytest **r, sArrayt *array) {
    472   sBytest *B = NULL;
    473 
    474   uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)array->type], array->count);
    475 
    476   forEachSArray(array, e) {
    477     if (!e) {
    478       // empty slots are represented as undefined elements
    479       sBytesPush(r, NET_SERIAL_TYPES[UNDEFINED]);
    480     }
    481     else {
    482       switch(e->type) {
    483         case UNDEFINED:
    484           sBytesPush(r, NET_SERIAL_TYPES[(u8)e->type]);
    485           break;
    486         case BOOL: {
    487             u8 c = NET_SERIAL_TYPES[(u8)e->type];
    488             // set bit 4 when true
    489             if (((sBoolt *)&(e->type))->value)
    490               c |= (1<<4);
    491             sBytesPush(r, c);
    492           }
    493           break;
    494         case CONTAINER:
    495           // undefined
    496           sBytesPush(r, NET_SERIAL_TYPES[(u8)e->type]);
    497           break;
    498         case DICT:
    499           dictNetSerialLevel0(r, (sDictt *)e);
    500           break;
    501         case DOUBLE:
    502           sBytesPush(r, NET_SERIAL_TYPES[(u8)e->type]);
    503           sBytesPushBuffer(r, &((sDoublet *)e)->value, sizeof(double));
    504           break;
    505         case INT: {
    506             // encode int to varint
    507             // v is int64_t to convert to varint
    508             i64 v = ((sIntt *)&(e->type))->value;
    509             // encode v with arithmetic shifts
    510             uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->type], (v << 1) ^ (v >> 63));
    511           }
    512           break;
    513         case STRING:
    514           sBytesPush(r, NET_SERIAL_TYPES[(u8)e->type]);
    515           sBytesPushBuffer(r, &((sStringt *)e)->data, sizeof(sStringt) + strlen(&(((sStringt *)e)->data)) -1);
    516           break;
    517         case ARRAY:
    518           arrayNetSerialLevel0(r, (sArrayt *)e);
    519           break;
    520         case BYTES:
    521           B = (sBytest *)e;
    522           uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->type], B->count);
    523           sBytesPushBuffer(r, &(B->data), B->count);
    524           break;
    525       }
    526     }
    527   }
    528   ret;
    529 }
    530 
    531 internal smallBytest* serialNetSerialLevel0(smallJsont *self) {
    532 
    533   smallt *o = getsoG(self);
    534 
    535   if (o == NULL)
    536     ret NULL;
    537 
    538   sBytest *B = netSerialLevel0(o);
    539 
    540   if (!B) {
    541     ret NULL;
    542   }
    543 
    544   createAllocateSmallBytes(r);
    545   r->B = B;
    546   ret r;
    547 }
    548 
    549 // level 1
    550 // like level 0 with type encoded in nibbles and bools are packed
    551 
    552 /**
    553  * serializer top function
    554  */
    555 internal sBytest* netSerialLevel1(smallt *o) {
    556   sBytest *r = NULL;
    557   sBytest *B = NULL;
    558   contextt ctx = {.nibble=lowNbl, .nblOffset=0, .boolShift = 0, .boolOffset=0};
    559 
    560   switch(o->type) {
    561     case UNDEFINED:
    562     case CONTAINER:
    563       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
    564       break;
    565     case BOOL: {
    566       u8 c = NET_SERIAL_TYPES[(u8)o->type];
    567       // set bit 4 when true
    568       if (((sBoolt *)&(o->type))->value)
    569         c |= (1<<4);
    570       sBytesPush(&r, c);
    571       }
    572       break;
    573     case DICT:
    574       dictNetSerialLevel1(&r, (sDictt *)&(o->type), &ctx);
    575       break;
    576     case DOUBLE:
    577       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
    578       sBytesPushBuffer(&r, &((sDoublet *)&(o->type))->value, sizeof(double));
    579       break;
    580     case INT: {
    581       // encode int to varint
    582       // v is int64_t to convert to varint
    583       i64 v = ((sIntt *)&(o->type))->value;
    584       // encode v with arithmetic shifts
    585       uintToNetTypeVarint(&r, NET_SERIAL_TYPES[(u8)o->type], (v << 1) ^ (v >> 63));
    586       }
    587       break;
    588     case STRING:
    589       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
    590       sBytesPushBuffer(&r, &((sStringt *)&(o->type))->data, sizeof(sStringt) + strlen(&(((sStringt *)&(o->type))->data)) -1);
    591       break;
    592     case ARRAY:
    593       arrayNetSerialLevel1(&r, (sArrayt *)&(o->type), &ctx);
    594       break;
    595     case BYTES:
    596       B = (sBytest *)&(o->type);
    597       uintToNetTypeVarint(&r, NET_SERIAL_TYPES[(u8)o->type], B->count);
    598       sBytesPushBuffer(&r, &(B->data), B->count);
    599       break;
    600   }
    601   ret r;
    602 }
    603 
    604 /**
    605  * serialize dictionary
    606  *
    607  * the serialized dict is pushed to r.
    608  * All elements are serialized recursively
    609  *
    610  * the data in containers is not serialized
    611  *
    612  * \param
    613  *   r small bytes object
    614  *   dict dictionary to serialize
    615  */
    616 internal void dictNetSerialLevel1(sBytest **r, sDictt *dict, contextt *ctx) {
    617   sBytest *B     = NULL;
    618   char    *data  = NULL;
    619 
    620   if (ctx->nibble == lowNbl) {
    621     uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)dict->type], dict->count);
    622   }
    623   else {
    624     // high nibble
    625     #define storeTypeInHighNbl(o)\
    626     ctx->nibble  = lowNbl;\
    627     data         = (char *)&((*r)->data) + ctx->nblOffset;\
    628     *data       |= NET_SERIAL_TYPES[(u8)o->type] << 4
    629     storeTypeInHighNbl(dict);
    630     uintToVarint(r, dict->count);
    631   }
    632 
    633   forEachSDict(dict, e) {
    634     if (e->key) {
    635       sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
    636 
    637       switch(e->data->type) {
    638         case UNDEFINED:
    639         case CONTAINER:
    640           if (ctx->nibble == lowNbl) {
    641             #define storeTypeOnly(o)\
    642             sBytesPush(r, NET_SERIAL_TYPES[(u8)o->type]);\
    643             ctx->nibble    = highNbl;\
    644             ctx->nblOffset = (*r)->count -1
    645             storeTypeOnly(e->data);
    646           }
    647           else {
    648             storeTypeInHighNbl(e->data);
    649           }
    650           break;
    651         case BOOL:
    652           if (!ctx->boolOffset) {
    653             // new packed bools
    654             if (ctx->nibble == lowNbl) {
    655               #define storeNew4bPackedBool(o)\
    656               u8 c = NET_SERIAL_TYPES[(u8)o->type];\
    657               /* set bit 4 when true */\
    658               if (((sBoolt *)(o))->value)\
    659                 c |= (1<<4);\
    660               sBytesPush(r, c);\
    661               ctx->boolShift  = 5;\
    662               ctx->boolOffset = (*r)->count -1
    663               storeNew4bPackedBool(e->data);
    664             }
    665             else {
    666               // high nibble, next byte is packed bools
    667               storeTypeInHighNbl(e->data);
    668               #define storeNew8bPackedBool(o)\
    669               u8 c         = 0;\
    670               if (((sBoolt *)(o))->value)\
    671                 c = 1;\
    672               sBytesPush(r, c);\
    673               ctx->boolShift  = 1;\
    674               ctx->boolOffset = (*r)->count -1
    675               storeNew8bPackedBool(e->data);
    676             }
    677           }
    678           else {
    679             // there was a bool before this one, fill bits in nibbles
    680             if (ctx->nibble == lowNbl) {
    681               if (ctx->boolShift == 8) {
    682                 // previous packed bool is full
    683                 // this byte is the new packed bools
    684                 storeNew4bPackedBool(e->data);
    685               }
    686               else {
    687                 storeTypeOnly(e->data);
    688                 #define storeBool(o)\
    689                 data           = (char *)&((*r)->data) + ctx->boolOffset;\
    690                 if (((sBoolt *)(o))->value)\
    691                   *data |= 1 << ctx->boolShift;\
    692                 ctx->boolShift++
    693                 storeBool(e->data);
    694               }
    695             }
    696             else {
    697               // high nibble
    698               storeTypeInHighNbl(e->data);
    699               if (ctx->boolShift == 8) {
    700                 // previous packed bool is full
    701                 // next byte is the new packed bools
    702                 storeNew8bPackedBool(e->data);
    703               }
    704               else {
    705                 storeBool(e->data);
    706               }
    707             }
    708           }
    709           break;
    710         case DICT:
    711           dictNetSerialLevel1(r, (sDictt *)(e->data), ctx);
    712           break;
    713         case DOUBLE:
    714           if (ctx->nibble == lowNbl) {
    715             storeTypeOnly(e->data);
    716           }
    717           else {
    718             // high nibble
    719             storeTypeInHighNbl(e->data);
    720           }
    721           sBytesPushBuffer(r, &((sDoublet *)(e->data))->value, sizeof(double));
    722           break;
    723         case INT: {
    724             // encode int to varint
    725             // v is int64_t to convert to varint
    726             i64 v = ((sIntt *)(e->data))->value;
    727             if (ctx->nibble == lowNbl) {
    728               // encode v with arithmetic shifts
    729               uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->data->type], (v << 1) ^ (v >> 63));
    730             }
    731             else {
    732               // high nibble
    733               storeTypeInHighNbl(e->data);
    734               uintToVarint(r, (v << 1) ^ (v >> 63));
    735             }
    736           }
    737           break;
    738         case STRING:
    739           if (ctx->nibble == lowNbl) {
    740             storeTypeOnly(e->data);
    741           }
    742           else {
    743             // high nibble
    744             storeTypeInHighNbl(e->data);
    745           }
    746           sBytesPushBuffer(r, &((sStringt *)(e->data))->data, sizeof(sStringt) + strlen(&(((sStringt *)(e->data))->data)) -1);
    747           break;
    748         case ARRAY:
    749           arrayNetSerialLevel1(r, (sArrayt *)(e->data), ctx);
    750           break;
    751         case BYTES:
    752           B = (sBytest *)(e->data);
    753           if (ctx->nibble == lowNbl) {
    754             uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->data->type], B->count);
    755           }
    756           else {
    757             // high nibble
    758             storeTypeInHighNbl(e->data);
    759             uintToVarint(r, B->count);
    760           }
    761           sBytesPushBuffer(r, &(B->data), B->count);
    762           break;
    763       }
    764     }
    765   }
    766   ret;
    767 }
    768 
    769 /**
    770  * serialize array
    771  *
    772  * the serialized array is pushed to r.
    773  * All elements are serialized recursively
    774  *
    775  * the data in containers is not serialized
    776  *
    777  * \param
    778  *   r small bytes object
    779  *   array to serialize
    780  */
    781 internal void arrayNetSerialLevel1(sBytest **r, sArrayt *array, contextt *ctx) {
    782   sBytest *B     = NULL;
    783   char    *data  = NULL;
    784 
    785   if (ctx->nibble == lowNbl) {
    786     uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)array->type], array->count);
    787   }
    788   else {
    789     // high nibble
    790     storeTypeInHighNbl(array);
    791     uintToVarint(r, array->count);
    792   }
    793 
    794   forEachSArray(array, e) {
    795     if (!e) {
    796       // empty slots are represented as undefined elements
    797       if (ctx->nibble == lowNbl) {
    798         sBytesPush(r, NET_SERIAL_TYPES[UNDEFINED]);
    799         ctx->nibble    = highNbl;
    800         ctx->nblOffset = (*r)->count -1;
    801       }
    802       else {
    803         // high nibble
    804         ctx->nibble  = lowNbl;
    805         data         = (char *)&((*r)->data) + ctx->nblOffset;
    806         *data       |= NET_SERIAL_TYPES[UNDEFINED] << 4;
    807       }
    808     }
    809     else {
    810       switch(e->type) {
    811         case UNDEFINED:
    812         case CONTAINER:
    813           if (ctx->nibble == lowNbl) {
    814             storeTypeOnly(e);
    815           }
    816           else {
    817             // high nibble
    818             storeTypeInHighNbl(e);
    819           }
    820           break;
    821         case BOOL:
    822           if (!ctx->boolOffset) {
    823             // new packed bools
    824             if (ctx->nibble == lowNbl) {
    825               storeNew4bPackedBool(e);
    826             }
    827             else {
    828               // high nibble, next byte is packed bools
    829               storeTypeInHighNbl(e);
    830               storeNew8bPackedBool(e);
    831             }
    832           }
    833           else {
    834             // there was a bool before this one, fill bits in nibbles
    835             if (ctx->nibble == lowNbl) {
    836               if (ctx->boolShift == 8) {
    837                 // previous packed bool is full
    838                 // this byte is the new packed bools
    839                 storeNew4bPackedBool(e);
    840               }
    841               else {
    842                 storeTypeOnly(e);
    843                 storeBool(e);
    844               }
    845             }
    846             else {
    847               // high nibble
    848               storeTypeInHighNbl(e);
    849               if (ctx->boolShift == 8) {
    850                 // previous packed bool is full
    851                 // next byte is the new packed bools
    852                 storeNew8bPackedBool(e);
    853               }
    854               else {
    855                 storeBool(e);
    856               }
    857             }
    858           }
    859           break;
    860         case DICT:
    861           dictNetSerialLevel1(r, (sDictt *)e, ctx);
    862           break;
    863         case DOUBLE:
    864           if (ctx->nibble == lowNbl) {
    865             storeTypeOnly(e);
    866           }
    867           else {
    868             // high nibble
    869             storeTypeInHighNbl(e);
    870           }
    871           sBytesPushBuffer(r, &((sDoublet *)e)->value, sizeof(double));
    872           break;
    873         case INT: {
    874             // encode int to varint
    875             // v is int64_t to convert to varint
    876             i64 v = ((sIntt *)&(e->type))->value;
    877             if (ctx->nibble == lowNbl) {
    878               // encode v with arithmetic shifts
    879               uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->type], (v << 1) ^ (v >> 63));
    880             }
    881             else {
    882               // high nibble
    883               storeTypeInHighNbl(e);
    884               uintToVarint(r, (v << 1) ^ (v >> 63));
    885             }
    886           }
    887           break;
    888         case STRING:
    889           if (ctx->nibble == lowNbl) {
    890             storeTypeOnly(e);
    891           }
    892           else {
    893             // high nibble
    894             storeTypeInHighNbl(e);
    895           }
    896           sBytesPushBuffer(r, &((sStringt *)e)->data, sizeof(sStringt) + strlen(&(((sStringt *)e)->data)) -1);
    897           break;
    898         case ARRAY:
    899           arrayNetSerialLevel1(r, (sArrayt *)e, ctx);
    900           break;
    901         case BYTES:
    902           B = (sBytest *)e;
    903           if (ctx->nibble == lowNbl) {
    904             uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->type], B->count);
    905           }
    906           else {
    907             // high nibble
    908             storeTypeInHighNbl(e);
    909             uintToVarint(r, B->count);
    910           }
    911           sBytesPushBuffer(r, &(B->data), B->count);
    912           break;
    913       }
    914     }
    915   }
    916   ret;
    917 }
    918 
    919 internal smallBytest* serialNetSerialLevel1(smallJsont *self) {
    920 
    921   smallt *o = getsoG(self);
    922 
    923   if (o == NULL)
    924     ret NULL;
    925 
    926   sBytest *B = netSerialLevel1(o);
    927 
    928   if (!B) {
    929     ret NULL;
    930   }
    931 
    932   createAllocateSmallBytes(r);
    933   r->B = B;
    934   ret r;
    935 }
    936 
    937 // level 2
    938 // like level 1, arrays are set to uniform when all elements are same type
    939 
    940 /**
    941  * serializer top function
    942  */
    943 internal sBytest* netSerialLevel2(smallt *o) {
    944   sBytest *r = NULL;
    945   sBytest *B = NULL;
    946   contextt ctx = {.nibble=lowNbl, .nblOffset=0, .boolShift = 0, .boolOffset=0};
    947 
    948   switch(o->type) {
    949     case UNDEFINED:
    950     case CONTAINER:
    951       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
    952       break;
    953     case BOOL: {
    954       u8 c = NET_SERIAL_TYPES[(u8)o->type];
    955       // set bit 4 when true
    956       if (((sBoolt *)&(o->type))->value)
    957         c |= (1<<4);
    958       sBytesPush(&r, c);
    959       }
    960       break;
    961     case DICT:
    962       dictNetSerialLevel2(&r, (sDictt *)&(o->type), &ctx, /*packed=*/false);
    963       break;
    964     case DOUBLE:
    965       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
    966       sBytesPushBuffer(&r, &((sDoublet *)&(o->type))->value, sizeof(double));
    967       break;
    968     case INT: {
    969       // encode int to varint
    970       // v is int64_t to convert to varint
    971       i64 v = ((sIntt *)&(o->type))->value;
    972       // encode v with arithmetic shifts
    973       uintToNetTypeVarint(&r, NET_SERIAL_TYPES[(u8)o->type], (v << 1) ^ (v >> 63));
    974       }
    975       break;
    976     case STRING:
    977       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
    978       sBytesPushBuffer(&r, &((sStringt *)&(o->type))->data, sizeof(sStringt) + strlen(&(((sStringt *)&(o->type))->data)) -1);
    979       break;
    980     case ARRAY:
    981       arrayNetSerialLevel2(&r, (sArrayt *)&(o->type), &ctx, /*packed=*/false);
    982       break;
    983     case BYTES:
    984       B = (sBytest *)&(o->type);
    985       uintToNetTypeVarint(&r, NET_SERIAL_TYPES[(u8)o->type], B->count);
    986       sBytesPushBuffer(&r, &(B->data), B->count);
    987       break;
    988   }
    989   ret r;
    990 }
    991 
    992 internal u8 isDictUniform(sDictt *dict) {
    993   bool allElementsHaveSameType = true;
    994   bool foundFirstType          = false;
    995   u8 type                      = 0;
    996   forEachSDict(dict, e) {
    997     if (e->key) {
    998       if (foundFirstType) {
    999         u8 nextType;
   1000         switch(e->data->type) {
   1001           case DICT:
   1002             nextType = isDictUniform((sDictt*)e->data);
   1003             break;
   1004           case ARRAY:
   1005             nextType = isArrayUniform((sArrayt*)e->data);
   1006             break;
   1007           default:
   1008             nextType = NET_SERIAL_TYPES[(u8)e->data->type];
   1009         }
   1010         if (nextType != type) {
   1011           allElementsHaveSameType = false;
   1012           break;
   1013         }
   1014       }
   1015       else {
   1016         switch(e->data->type) {
   1017           case DICT:
   1018             type = isDictUniform((sDictt*)e->data);
   1019             break;
   1020           case ARRAY:
   1021             type = isArrayUniform((sArrayt*)e->data);
   1022             break;
   1023           default:
   1024             type = NET_SERIAL_TYPES[(u8)e->data->type];
   1025         }
   1026         foundFirstType = true;
   1027       }
   1028     }
   1029   }
   1030   if (allElementsHaveSameType)
   1031     type = UNIFORM_DICT;
   1032   else
   1033     type = S_DICT;
   1034   ret type;
   1035 }
   1036 
   1037 internal u8 isArrayUniform(sArrayt *array) {
   1038   bool allElementsHaveSameType = true;
   1039   bool foundFirstType          = false;
   1040   char type                    = 0;
   1041   forEachSArray(array, e) {
   1042     if (!e) {
   1043       if (foundFirstType) {
   1044         if (type != S_UNDEFINED) {
   1045           allElementsHaveSameType = false;
   1046           break;
   1047         }
   1048       }
   1049       else {
   1050         type = S_UNDEFINED;
   1051         foundFirstType = true;
   1052       }
   1053     }
   1054     else {
   1055       if (foundFirstType) {
   1056         u8 nextType;
   1057         switch(e->type) {
   1058           case DICT:
   1059             nextType = isDictUniform((sDictt*)e);
   1060             break;
   1061           case ARRAY:
   1062             nextType = isArrayUniform((sArrayt*)e);
   1063             break;
   1064           default:
   1065             nextType = NET_SERIAL_TYPES[(u8)e->type];
   1066         }
   1067         if (nextType != type) {
   1068           allElementsHaveSameType = false;
   1069           break;
   1070         }
   1071       }
   1072       else {
   1073         switch(e->type) {
   1074           case DICT:
   1075             type = isDictUniform((sDictt*)e);
   1076             break;
   1077           case ARRAY:
   1078             type = isArrayUniform((sArrayt*)e);
   1079             break;
   1080           default:
   1081             type = NET_SERIAL_TYPES[(u8)e->type];
   1082         }
   1083         foundFirstType = true;
   1084       }
   1085     }
   1086   }
   1087   if (allElementsHaveSameType)
   1088     type = UNIFORM_ARRAY;
   1089   else
   1090     type = S_ARRAY;
   1091   ret type;
   1092 }
   1093 
   1094 /**
   1095  * serialize dictionary
   1096  *
   1097  * the serialized dict is pushed to r.
   1098  * All elements are serialized recursively
   1099  *
   1100  * the data in containers is not serialized
   1101  *
   1102  * \param
   1103  *   r small bytes object
   1104  *   dict dictionary to serialize
   1105  */
   1106 internal void dictNetSerialLevel2(sBytest **r, sDictt *dict, contextt *ctx, bool packed) {
   1107   sBytest *B     = NULL;
   1108   char    *data  = NULL;
   1109 
   1110   // check if all elements have same type
   1111   bool allElementsHaveSameType = true;
   1112   bool foundFirstType          = false;
   1113   char type                    = 0;
   1114   {forEachSDict(dict, e) {
   1115     if (e->key) {
   1116       if (foundFirstType) {
   1117         u8 nextType;
   1118         switch(e->data->type) {
   1119           case DICT:
   1120             nextType = isDictUniform((sDictt*)e->data);
   1121             break;
   1122           case ARRAY:
   1123             nextType = isArrayUniform((sArrayt*)e->data);
   1124             break;
   1125           default:
   1126             nextType = NET_SERIAL_TYPES[(u8)e->data->type];
   1127         }
   1128         if (nextType != type) {
   1129           allElementsHaveSameType = false;
   1130           break;
   1131         }
   1132       }
   1133       else {
   1134         switch(e->data->type) {
   1135           case DICT:
   1136             type = isDictUniform((sDictt*)e->data);
   1137             break;
   1138           case ARRAY:
   1139             type = isArrayUniform((sArrayt*)e->data);
   1140             break;
   1141           default:
   1142             type = NET_SERIAL_TYPES[(u8)e->data->type];
   1143         }
   1144         foundFirstType = true;
   1145       }
   1146     }
   1147   }}
   1148 
   1149   if (allElementsHaveSameType) {
   1150     // pack dictionary
   1151     if (packed) {
   1152       uintToNetTypeVarint(r, type, dict->count);
   1153     }
   1154     else {
   1155       if (ctx->nibble == lowNbl) {
   1156         sBytesPush(r, (type << 4) + UNIFORM_DICT);
   1157         uintToVarint(r, dict->count);
   1158       }
   1159       else {
   1160         // high nibble
   1161         ctx->nibble  = lowNbl;
   1162         data         = (char *)&((*r)->data) + ctx->nblOffset;
   1163         *data       |= UNIFORM_DICT << 4;
   1164         uintToNetTypeVarint(r, type, dict->count);
   1165       }
   1166     }
   1167 
   1168     switch(type) {
   1169       case S_UNDEFINED:
   1170         {forEachSDict(dict, e) {
   1171           if (e->key) {
   1172             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1173           }
   1174         }}
   1175 
   1176         break;
   1177       case S_BOOL:
   1178         {forEachSDict(dict, e) {
   1179           if (e->key) {
   1180             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1181 
   1182             if (!ctx->boolOffset) {
   1183               // new packed bools
   1184               storeNew8bPackedBool(e->data);
   1185             }
   1186             else {
   1187               // there was a bool before this one, fill bits in nibbles
   1188               if (ctx->boolShift == 8) {
   1189                 // previous packed bool is full
   1190                 // next byte is the new packed bools
   1191                 storeNew8bPackedBool(e->data);
   1192               }
   1193               else {
   1194                 storeBool(e->data);
   1195               }
   1196             }
   1197           }
   1198         }}
   1199         break;
   1200       case S_DICT:
   1201       case UNIFORM_DICT:
   1202         {forEachSDict(dict, e) {
   1203           if (e->key) {
   1204             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1205             dictNetSerialLevel2(r, (sDictt *)(e->data), ctx, /*packed=*/true);
   1206           }
   1207         }}
   1208         break;
   1209       case S_DOUBLE:
   1210         {forEachSDict(dict, e) {
   1211           if (e->key) {
   1212             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1213             sBytesPushBuffer(r, &((sDoublet *)(e->data))->value, sizeof(double));
   1214           }
   1215         }}
   1216         break;
   1217       case S_INT:
   1218         {forEachSDict(dict, e) {
   1219           if (e->key) {
   1220             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1221             i64 v = ((sIntt *)(e->data))->value;
   1222             uintToVarint(r, (v << 1) ^ (v >> 63));
   1223           }
   1224         }}
   1225         break;
   1226       case S_STRING:
   1227         {forEachSDict(dict, e) {
   1228           if (e->key) {
   1229             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1230             sBytesPushBuffer(r, &((sStringt *)(e->data))->data, sizeof(sStringt) + strlen(&(((sStringt *)(e->data))->data)) -1);
   1231           }
   1232         }}
   1233         break;
   1234       case S_ARRAY:
   1235       case UNIFORM_ARRAY:
   1236         {forEachSDict(dict, e) {
   1237           if (e->key) {
   1238             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1239             arrayNetSerialLevel2(r, (sArrayt *)(e->data), ctx, /*packed=*/true);
   1240           }
   1241         }}
   1242         break;
   1243       case S_BYTES:
   1244         {forEachSDict(dict, e) {
   1245           if (e->key) {
   1246             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1247             B = (sBytest *)(e->data);
   1248             uintToVarint(r, B->count);
   1249             sBytesPushBuffer(r, &(B->data), B->count);
   1250           }
   1251         }}
   1252         break;
   1253     }
   1254     ret;
   1255   }
   1256 
   1257   if (packed) {
   1258     uintToVarint(r, dict->count);
   1259   }
   1260   else {
   1261     if (ctx->nibble == lowNbl) {
   1262       uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)dict->type], dict->count);
   1263     }
   1264     else {
   1265       // high nibble
   1266 #define storeTypeInHighNbl(o)\
   1267       ctx->nibble  = lowNbl;\
   1268       data         = (char *)&((*r)->data) + ctx->nblOffset;\
   1269       *data       |= NET_SERIAL_TYPES[(u8)o->type] << 4
   1270       storeTypeInHighNbl(dict);
   1271       uintToVarint(r, dict->count);
   1272     }
   1273   }
   1274 
   1275   forEachSDict(dict, e) {
   1276     if (e->key) {
   1277       sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1278 
   1279       switch(e->data->type) {
   1280         case UNDEFINED:
   1281         case CONTAINER:
   1282           if (ctx->nibble == lowNbl) {
   1283             #define storeTypeOnly(o)\
   1284             sBytesPush(r, NET_SERIAL_TYPES[(u8)o->type]);\
   1285             ctx->nibble    = highNbl;\
   1286             ctx->nblOffset = (*r)->count -1
   1287             storeTypeOnly(e->data);
   1288           }
   1289           else {
   1290             storeTypeInHighNbl(e->data);
   1291           }
   1292           break;
   1293         case BOOL:
   1294           if (!ctx->boolOffset) {
   1295             // new packed bools
   1296             if (ctx->nibble == lowNbl) {
   1297               #define storeNew4bPackedBool(o)\
   1298               u8 c = NET_SERIAL_TYPES[(u8)o->type];\
   1299               /* set bit 4 when true */\
   1300               if (((sBoolt *)(o))->value)\
   1301                 c |= (1<<4);\
   1302               sBytesPush(r, c);\
   1303               ctx->boolShift  = 5;\
   1304               ctx->boolOffset = (*r)->count -1
   1305               storeNew4bPackedBool(e->data);
   1306             }
   1307             else {
   1308               // high nibble, next byte is packed bools
   1309               storeTypeInHighNbl(e->data);
   1310               #define storeNew8bPackedBool(o)\
   1311               u8 c         = 0;\
   1312               if (((sBoolt *)(o))->value)\
   1313                 c = 1;\
   1314               sBytesPush(r, c);\
   1315               ctx->boolShift  = 1;\
   1316               ctx->boolOffset = (*r)->count -1
   1317               storeNew8bPackedBool(e->data);
   1318             }
   1319           }
   1320           else {
   1321             // there was a bool before this one, fill bits in nibbles
   1322             if (ctx->nibble == lowNbl) {
   1323               if (ctx->boolShift == 8) {
   1324                 // previous packed bool is full
   1325                 // this byte is the new packed bools
   1326                 storeNew4bPackedBool(e->data);
   1327               }
   1328               else {
   1329                 storeTypeOnly(e->data);
   1330                 #define storeBool(o)\
   1331                 data           = (char *)&((*r)->data) + ctx->boolOffset;\
   1332                 if (((sBoolt *)(o))->value)\
   1333                   *data |= 1 << ctx->boolShift;\
   1334                 ctx->boolShift++
   1335                 storeBool(e->data);
   1336               }
   1337             }
   1338             else {
   1339               // high nibble
   1340               storeTypeInHighNbl(e->data);
   1341               if (ctx->boolShift == 8) {
   1342                 // previous packed bool is full
   1343                 // next byte is the new packed bools
   1344                 storeNew8bPackedBool(e->data);
   1345               }
   1346               else {
   1347                 storeBool(e->data);
   1348               }
   1349             }
   1350           }
   1351           break;
   1352         case DICT:
   1353           dictNetSerialLevel2(r, (sDictt *)(e->data), ctx, /*packed=*/false);
   1354           break;
   1355         case DOUBLE:
   1356           if (ctx->nibble == lowNbl) {
   1357             storeTypeOnly(e->data);
   1358           }
   1359           else {
   1360             // high nibble
   1361             storeTypeInHighNbl(e->data);
   1362           }
   1363           sBytesPushBuffer(r, &((sDoublet *)(e->data))->value, sizeof(double));
   1364           break;
   1365         case INT: {
   1366             // encode int to varint
   1367             // v is int64_t to convert to varint
   1368             i64 v = ((sIntt *)(e->data))->value;
   1369             if (ctx->nibble == lowNbl) {
   1370               // encode v with arithmetic shifts
   1371               uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->data->type], (v << 1) ^ (v >> 63));
   1372             }
   1373             else {
   1374               // high nibble
   1375               storeTypeInHighNbl(e->data);
   1376               uintToVarint(r, (v << 1) ^ (v >> 63));
   1377             }
   1378           }
   1379           break;
   1380         case STRING:
   1381           if (ctx->nibble == lowNbl) {
   1382             storeTypeOnly(e->data);
   1383           }
   1384           else {
   1385             // high nibble
   1386             storeTypeInHighNbl(e->data);
   1387           }
   1388           sBytesPushBuffer(r, &((sStringt *)(e->data))->data, sizeof(sStringt) + strlen(&(((sStringt *)(e->data))->data)) -1);
   1389           break;
   1390         case ARRAY:
   1391           arrayNetSerialLevel2(r, (sArrayt *)(e->data), ctx, /*packed=*/false);
   1392           break;
   1393         case BYTES:
   1394           B = (sBytest *)(e->data);
   1395           if (ctx->nibble == lowNbl) {
   1396             uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->data->type], B->count);
   1397           }
   1398           else {
   1399             // high nibble
   1400             storeTypeInHighNbl(e->data);
   1401             uintToVarint(r, B->count);
   1402           }
   1403           sBytesPushBuffer(r, &(B->data), B->count);
   1404           break;
   1405       }
   1406     }
   1407   }
   1408   ret;
   1409 }
   1410 
   1411 /**
   1412  * serialize array
   1413  *
   1414  * the serialized array is pushed to r.
   1415  * All elements are serialized recursively
   1416  *
   1417  * the data in containers is not serialized
   1418  *
   1419  * \param
   1420  *   r small bytes object
   1421  *   array to serialize
   1422  */
   1423 internal void arrayNetSerialLevel2(sBytest **r, sArrayt *array, contextt *ctx, bool packed) {
   1424   sBytest *B     = NULL;
   1425   char    *data  = NULL;
   1426 
   1427   // check if all elements have same type
   1428   bool allElementsHaveSameType = true;
   1429   bool foundFirstType          = false;
   1430   char type                    = 0;
   1431 
   1432   {forEachSArray(array, e) {
   1433     if (!e) {
   1434       if (foundFirstType) {
   1435         if (type != S_UNDEFINED) {
   1436           allElementsHaveSameType = false;
   1437           break;
   1438         }
   1439       }
   1440       else {
   1441         type = S_UNDEFINED;
   1442         foundFirstType = true;
   1443       }
   1444     }
   1445     else {
   1446       if (foundFirstType) {
   1447         u8 nextType;
   1448         switch(e->type) {
   1449           case DICT:
   1450             nextType = isDictUniform((sDictt*)e);
   1451             break;
   1452           case ARRAY:
   1453             nextType = isArrayUniform((sArrayt*)e);
   1454             break;
   1455           default:
   1456             nextType = NET_SERIAL_TYPES[(u8)e->type];
   1457         }
   1458         if (nextType != type) {
   1459           allElementsHaveSameType = false;
   1460           break;
   1461         }
   1462       }
   1463       else {
   1464         switch(e->type) {
   1465           case DICT:
   1466             type = isDictUniform((sDictt*)e);
   1467             break;
   1468           case ARRAY:
   1469             type = isArrayUniform((sArrayt*)e);
   1470             break;
   1471           default:
   1472             type = NET_SERIAL_TYPES[(u8)e->type];
   1473         }
   1474         foundFirstType = true;
   1475       }
   1476     }
   1477   }}
   1478 
   1479   if (allElementsHaveSameType) {
   1480     // pack array
   1481     if (packed) {
   1482       uintToNetTypeVarint(r, type, array->count);
   1483     }
   1484     else {
   1485       if (ctx->nibble == lowNbl) {
   1486         sBytesPush(r, (type << 4) + UNIFORM_ARRAY);
   1487         uintToVarint(r, array->count);
   1488       }
   1489       else {
   1490         // high nibble
   1491         ctx->nibble  = lowNbl;
   1492         data         = (char *)&((*r)->data) + ctx->nblOffset;
   1493         *data       |= UNIFORM_ARRAY << 4;
   1494         uintToNetTypeVarint(r, type, array->count);
   1495       }
   1496     }
   1497 
   1498     switch(type) {
   1499       case S_BOOL:
   1500         {forEachSArray(array, e) {
   1501           if (!ctx->boolOffset) {
   1502             // new packed bools
   1503             storeNew8bPackedBool(e);
   1504           }
   1505           else {
   1506             // there was a bool before this one, fill bits in nibbles
   1507             if (ctx->boolShift == 8) {
   1508               // previous packed bool is full
   1509               // next byte is the new packed bools
   1510               storeNew8bPackedBool(e);
   1511             }
   1512             else {
   1513               storeBool(e);
   1514             }
   1515           }
   1516         }}
   1517         break;
   1518       case S_DICT:
   1519       case UNIFORM_DICT:
   1520         {forEachSArray(array, e) {
   1521           dictNetSerialLevel2(r, (sDictt *)e, ctx, /*packed=*/true);
   1522         }}
   1523         break;
   1524       case S_DOUBLE:
   1525         {forEachSArray(array, e) {
   1526           sBytesPushBuffer(r, &((sDoublet *)e)->value, sizeof(double));
   1527         }}
   1528         break;
   1529       case S_INT:
   1530         {forEachSArray(array, e) {
   1531           i64 v = ((sIntt *)e)->value;
   1532           uintToVarint(r, (v << 1) ^ (v >> 63));
   1533         }}
   1534         break;
   1535       case S_STRING:
   1536         {forEachSArray(array, e) {
   1537           sBytesPushBuffer(r, &((sStringt *)e)->data, sizeof(sStringt) + strlen(&(((sStringt *)e)->data)) -1);
   1538         }}
   1539         break;
   1540       case S_ARRAY:
   1541       case UNIFORM_ARRAY:
   1542         {forEachSArray(array, e) {
   1543           arrayNetSerialLevel2(r, (sArrayt *)e, ctx, /*packed=*/true);
   1544         }}
   1545         break;
   1546       case S_BYTES:
   1547         {forEachSArray(array, e) {
   1548           B = (sBytest *)e;
   1549           uintToVarint(r, B->count);
   1550           sBytesPushBuffer(r, &(B->data), B->count);
   1551         }}
   1552         break;
   1553     }
   1554     ret;
   1555   }
   1556 
   1557   if (packed) {
   1558     uintToVarint(r, array->count);
   1559   }
   1560   else {
   1561     if (ctx->nibble == lowNbl) {
   1562       uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)array->type], array->count);
   1563     }
   1564     else {
   1565       // high nibble
   1566       storeTypeInHighNbl(array);
   1567       uintToVarint(r, array->count);
   1568     }
   1569   }
   1570 
   1571   forEachSArray(array, e) {
   1572     if (!e) {
   1573       // empty slots are represented as undefined elements
   1574       if (ctx->nibble == lowNbl) {
   1575         sBytesPush(r, NET_SERIAL_TYPES[UNDEFINED]);
   1576         ctx->nibble    = highNbl;
   1577         ctx->nblOffset = (*r)->count -1;
   1578       }
   1579       else {
   1580         // high nibble
   1581         ctx->nibble  = lowNbl;
   1582         data         = (char *)&((*r)->data) + ctx->nblOffset;
   1583         *data       |= NET_SERIAL_TYPES[UNDEFINED] << 4;
   1584       }
   1585     }
   1586     else {
   1587       switch(e->type) {
   1588         case UNDEFINED:
   1589         case CONTAINER:
   1590           if (ctx->nibble == lowNbl) {
   1591             storeTypeOnly(e);
   1592           }
   1593           else {
   1594             // high nibble
   1595             storeTypeInHighNbl(e);
   1596           }
   1597           break;
   1598         case BOOL:
   1599           if (!ctx->boolOffset) {
   1600             // new packed bools
   1601             if (ctx->nibble == lowNbl) {
   1602               storeNew4bPackedBool(e);
   1603             }
   1604             else {
   1605               // high nibble, next byte is packed bools
   1606               storeTypeInHighNbl(e);
   1607               storeNew8bPackedBool(e);
   1608             }
   1609           }
   1610           else {
   1611             // there was a bool before this one, fill bits in nibbles
   1612             if (ctx->nibble == lowNbl) {
   1613               if (ctx->boolShift == 8) {
   1614                 // previous packed bool is full
   1615                 // this byte is the new packed bools
   1616                 storeNew4bPackedBool(e);
   1617               }
   1618               else {
   1619                 storeTypeOnly(e);
   1620                 storeBool(e);
   1621               }
   1622             }
   1623             else {
   1624               // high nibble
   1625               storeTypeInHighNbl(e);
   1626               if (ctx->boolShift == 8) {
   1627                 // previous packed bool is full
   1628                 // next byte is the new packed bools
   1629                 storeNew8bPackedBool(e);
   1630               }
   1631               else {
   1632                 storeBool(e);
   1633               }
   1634             }
   1635           }
   1636           break;
   1637         case DICT:
   1638           dictNetSerialLevel2(r, (sDictt *)e, ctx, /*packed=*/false);
   1639           break;
   1640         case DOUBLE:
   1641           if (ctx->nibble == lowNbl) {
   1642             storeTypeOnly(e);
   1643           }
   1644           else {
   1645             // high nibble
   1646             storeTypeInHighNbl(e);
   1647           }
   1648           sBytesPushBuffer(r, &((sDoublet *)e)->value, sizeof(double));
   1649           break;
   1650         case INT: {
   1651             // encode int to varint
   1652             // v is int64_t to convert to varint
   1653             i64 v = ((sIntt *)&(e->type))->value;
   1654             if (ctx->nibble == lowNbl) {
   1655               // encode v with arithmetic shifts
   1656               uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->type], (v << 1) ^ (v >> 63));
   1657             }
   1658             else {
   1659               // high nibble
   1660               storeTypeInHighNbl(e);
   1661               uintToVarint(r, (v << 1) ^ (v >> 63));
   1662             }
   1663           }
   1664           break;
   1665         case STRING:
   1666           if (ctx->nibble == lowNbl) {
   1667             storeTypeOnly(e);
   1668           }
   1669           else {
   1670             // high nibble
   1671             storeTypeInHighNbl(e);
   1672           }
   1673           sBytesPushBuffer(r, &((sStringt *)e)->data, sizeof(sStringt) + strlen(&(((sStringt *)e)->data)) -1);
   1674           break;
   1675         case ARRAY:
   1676           arrayNetSerialLevel2(r, (sArrayt *)e, ctx, /*packed=*/false);
   1677           break;
   1678         case BYTES:
   1679           B = (sBytest *)e;
   1680           if (ctx->nibble == lowNbl) {
   1681             uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->type], B->count);
   1682           }
   1683           else {
   1684             // high nibble
   1685             storeTypeInHighNbl(e);
   1686             uintToVarint(r, B->count);
   1687           }
   1688           sBytesPushBuffer(r, &(B->data), B->count);
   1689           break;
   1690       }
   1691     }
   1692   }
   1693   ret;
   1694 }
   1695 
   1696 internal smallBytest* serialNetSerialLevel2(smallJsont *self) {
   1697 
   1698   smallt *o = getsoG(self);
   1699 
   1700   if (o == NULL)
   1701     ret NULL;
   1702 
   1703   sBytest *B = netSerialLevel2(o);
   1704 
   1705   if (!B) {
   1706     ret NULL;
   1707   }
   1708 
   1709   createAllocateSmallBytes(r);
   1710   r->B = B;
   1711   ret r;
   1712 }
   1713 
   1714 // level 3
   1715 // like level 2, elements of identical type in a row are packed
   1716 
   1717 /**
   1718  * serializer top function
   1719  */
   1720 internal sBytest* netSerial(smallt *o) {
   1721   sBytest *r = NULL;
   1722   sBytest *B = NULL;
   1723   contextt ctx = {.nibble=lowNbl, .nblOffset=0, .boolShift = 0, .boolOffset=0};
   1724 
   1725   switch(o->type) {
   1726     case UNDEFINED:
   1727     case CONTAINER:
   1728       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
   1729       break;
   1730     case BOOL: {
   1731       u8 c = NET_SERIAL_TYPES[(u8)o->type];
   1732       // set bit 4 when true
   1733       if (((sBoolt *)&(o->type))->value)
   1734         c |= (1<<4);
   1735       sBytesPush(&r, c);
   1736       }
   1737       break;
   1738     case DICT:
   1739       dictNetSerial(&r, (sDictt *)&(o->type), &ctx, /*packing=*/NOPACKING);
   1740       break;
   1741     case DOUBLE:
   1742       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
   1743       sBytesPushBuffer(&r, &((sDoublet *)&(o->type))->value, sizeof(double));
   1744       break;
   1745     case INT: {
   1746       // encode int to varint
   1747       // v is int64_t to convert to varint
   1748       i64 v = ((sIntt *)&(o->type))->value;
   1749       // encode v with arithmetic shifts
   1750       uintToNetTypeVarint(&r, NET_SERIAL_TYPES[(u8)o->type], (v << 1) ^ (v >> 63));
   1751       }
   1752       break;
   1753     case STRING:
   1754       sBytesPush(&r, NET_SERIAL_TYPES[(u8)o->type]);
   1755       sBytesPushBuffer(&r, &((sStringt *)&(o->type))->data, sizeof(sStringt) + strlen(&(((sStringt *)&(o->type))->data)) -1);
   1756       break;
   1757     case ARRAY:
   1758       arrayNetSerial(&r, (sArrayt *)&(o->type), &ctx, /*packing=*/NOPACKING);
   1759       break;
   1760     case BYTES:
   1761       B = (sBytest *)&(o->type);
   1762       uintToNetTypeVarint(&r, NET_SERIAL_TYPES[(u8)o->type], B->count);
   1763       sBytesPushBuffer(&r, &(B->data), B->count);
   1764       break;
   1765   }
   1766   ret r;
   1767 }
   1768 
   1769 /**
   1770  * serialize dictionary
   1771  *
   1772  * the serialized dict is pushed to r.
   1773  * All elements are serialized recursively
   1774  *
   1775  * the data in containers is not serialized
   1776  *
   1777  * \param
   1778  *   r small bytes object
   1779  *   dict dictionary to serialize
   1780  */
   1781 internal void dictNetSerial(sBytest **r, sDictt *dict, contextt *ctx, packingT packing) {
   1782   sBytest *B     = NULL;
   1783   char    *data  = NULL;
   1784 
   1785   // compute allocated element count and use that instead of dict->count
   1786   // when elements are deleted, some positions are NULL
   1787   // and should not be counted
   1788   u32 cnt =0;
   1789   {forEachSDict(dict, e) {
   1790     if (e->key) {
   1791       inc cnt;
   1792     }
   1793   }}
   1794 
   1795   // check if all elements have same type
   1796   // then set dict type normal or uniform
   1797   // array and dict have to be checked recursively to know if they are normal or uniform
   1798   bool allElementsHaveSameType = true;
   1799   bool foundFirstType          = false;
   1800   char type                    = 0;
   1801   // get first element type
   1802   // compare to other element type
   1803   {forEachSDict(dict, e) {
   1804     if (e->key) {
   1805       if (foundFirstType) {
   1806         u8 nextType;
   1807         switch(e->data->type) {
   1808           case DICT:
   1809             nextType = isDictUniform((sDictt*)e->data);
   1810             break;
   1811           case ARRAY:
   1812             nextType = isArrayUniform((sArrayt*)e->data);
   1813             break;
   1814           default:
   1815             nextType = NET_SERIAL_TYPES[(u8)e->data->type];
   1816         }
   1817         if (nextType != type) {
   1818           allElementsHaveSameType = false;
   1819           break;
   1820         }
   1821       }
   1822       else {
   1823         switch(e->data->type) {
   1824           case DICT:
   1825             type = isDictUniform((sDictt*)e->data);
   1826             break;
   1827           case ARRAY:
   1828             type = isArrayUniform((sArrayt*)e->data);
   1829             break;
   1830           default:
   1831             type = NET_SERIAL_TYPES[(u8)e->data->type];
   1832         }
   1833         foundFirstType = true;
   1834       }
   1835     }
   1836   }}
   1837 
   1838   if (allElementsHaveSameType) {
   1839     // uniform dict
   1840     // encode type and element count
   1841 
   1842     // in pack dictionary
   1843     if (packing == PACK) {
   1844       // uniform dict can't be packed
   1845       // because there is only one type of packed arrays
   1846       goto normalDict;
   1847     }
   1848     elif (packing == UNIFORM) {
   1849       // when the packing is uniform, there is no need to encode UNIFORM_DICT since all elements have this type
   1850       uintToNetTypeVarint(r, type, cnt);
   1851     }
   1852     else {
   1853       if (ctx->nibble == lowNbl) {
   1854         sBytesPush(r, (type << 4) + UNIFORM_DICT);
   1855         uintToVarint(r, cnt);
   1856       }
   1857       else {
   1858         // high nibble
   1859         ctx->nibble  = lowNbl;
   1860         data         = (char *)&((*r)->data) + ctx->nblOffset;
   1861         *data       |= UNIFORM_DICT << 4;
   1862         uintToNetTypeVarint(r, type, cnt);
   1863       }
   1864     }
   1865 
   1866     // encode all element keys and values
   1867     switch(type) {
   1868       case S_UNDEFINED:
   1869         {forEachSDict(dict, e) {
   1870           if (e->key) {
   1871             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1872           }
   1873         }}
   1874 
   1875         break;
   1876       case S_BOOL:
   1877         {forEachSDict(dict, e) {
   1878           if (e->key) {
   1879             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1880 
   1881             if (!ctx->boolOffset) {
   1882               // new packed bools
   1883               storeNew8bPackedBool(e->data);
   1884             }
   1885             else {
   1886               // there was a bool before this one, fill bits in nibbles
   1887               if (ctx->boolShift == 8) {
   1888                 // previous packed bool is full
   1889                 // next byte is the new packed bools
   1890                 storeNew8bPackedBool(e->data);
   1891               }
   1892               else {
   1893                 storeBool(e->data);
   1894               }
   1895             }
   1896           }
   1897         }}
   1898         break;
   1899       case S_DICT:
   1900       case UNIFORM_DICT:
   1901         {forEachSDict(dict, e) {
   1902           if (e->key) {
   1903             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1904             dictNetSerial(r, (sDictt *)(e->data), ctx, /*packing=*/UNIFORM);
   1905           }
   1906         }}
   1907         break;
   1908       case S_DOUBLE:
   1909         {forEachSDict(dict, e) {
   1910           if (e->key) {
   1911             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1912             sBytesPushBuffer(r, &((sDoublet *)(e->data))->value, sizeof(double));
   1913           }
   1914         }}
   1915         break;
   1916       case S_INT:
   1917         {forEachSDict(dict, e) {
   1918           if (e->key) {
   1919             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1920             i64 v = ((sIntt *)(e->data))->value;
   1921             uintToVarint(r, (v << 1) ^ (v >> 63));
   1922           }
   1923         }}
   1924         break;
   1925       case S_STRING:
   1926         {forEachSDict(dict, e) {
   1927           if (e->key) {
   1928             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1929             sBytesPushBuffer(r, &((sStringt *)(e->data))->data, sizeof(sStringt) + strlen(&(((sStringt *)(e->data))->data)) -1);
   1930           }
   1931         }}
   1932         break;
   1933       case S_ARRAY:
   1934       case UNIFORM_ARRAY:
   1935         {forEachSDict(dict, e) {
   1936           if (e->key) {
   1937             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1938             arrayNetSerial(r, (sArrayt *)(e->data), ctx, /*packing=*/UNIFORM);
   1939           }
   1940         }}
   1941         break;
   1942       case S_BYTES:
   1943         {forEachSDict(dict, e) {
   1944           if (e->key) {
   1945             sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   1946             B = (sBytest *)(e->data);
   1947             uintToVarint(r, B->count);
   1948             sBytesPushBuffer(r, &(B->data), B->count);
   1949           }
   1950         }}
   1951         break;
   1952     }
   1953     ret;
   1954   }
   1955 
   1956   normalDict:
   1957   // encode type and element count
   1958   if (packing == PACK or packing == UNIFORM) {
   1959     // when the packing is packed or uniform, there is no need to encode DICT type since all elements have this type
   1960     uintToVarint(r, cnt);
   1961   }
   1962   else {
   1963     if (ctx->nibble == lowNbl) {
   1964       uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)dict->type], cnt);
   1965     }
   1966     else {
   1967       // high nibble
   1968       #define storeTypeInHighNbl(o)\
   1969       ctx->nibble  = lowNbl;\
   1970       data         = (char *)&((*r)->data) + ctx->nblOffset;\
   1971       *data       |= NET_SERIAL_TYPES[(u8)o->type] << 4
   1972       storeTypeInHighNbl(dict);
   1973       uintToVarint(r, cnt);
   1974     }
   1975   }
   1976 
   1977   bool   pack = false;
   1978   size_t packCount;
   1979   enumerateSDict(dict, e, eIdx) {
   1980     if (e->key) {
   1981       if (!pack) {
   1982         // scan dict for packing
   1983         if ((cnt - eIdx) > 3) {
   1984           // at least 4 elements, less than that is not worth it
   1985           if (   e->data->type == DICT
   1986               or e->data->type == DOUBLE
   1987               or e->data->type == INT
   1988               or e->data->type == STRING
   1989               or e->data->type == ARRAY
   1990               or e->data->type == BYTES) {
   1991             type      = e->data->type;
   1992             packCount = 1;
   1993             sDictElemt *element = &((dict)->elements) + eIdx +1;
   1994             for (size_t i = eIdx+1; i < (dict)->count ; i++, element = &((dict)->elements) + i) {
   1995               if (element->key) {
   1996                 if (element->data->type != type) {
   1997                   break;
   1998                 }
   1999                 packCount++;
   2000               } // element->key
   2001             } // for
   2002             if (packCount > 3) {
   2003               type = PACKED_NET_SERIAL_TYPES[(u8)type];
   2004               pack = true;
   2005             }
   2006           } // test current element type
   2007         } // is dict big enough
   2008       } // not already packing
   2009 
   2010       // encode key
   2011       sBytesPushBuffer(r, e->key, strlen(e->key) + 1);
   2012 
   2013       // encode value
   2014       switch(e->data->type) {
   2015         case UNDEFINED:
   2016         case CONTAINER:
   2017           if (ctx->nibble == lowNbl) {
   2018             #define storeTypeOnly(o)\
   2019             sBytesPush(r, NET_SERIAL_TYPES[(u8)o->type]);\
   2020             ctx->nibble    = highNbl;\
   2021             ctx->nblOffset = (*r)->count -1
   2022             storeTypeOnly(e->data);
   2023           }
   2024           else {
   2025             storeTypeInHighNbl(e->data);
   2026           }
   2027           break;
   2028         case BOOL:
   2029           if (!ctx->boolOffset) {
   2030             // new packed bools
   2031             if (ctx->nibble == lowNbl) {
   2032               #define storeNew4bPackedBool(o)\
   2033               u8 c = NET_SERIAL_TYPES[(u8)o->type];\
   2034               /* set bit 4 when true */\
   2035               if (((sBoolt *)(o))->value)\
   2036                 c |= (1<<4);\
   2037               sBytesPush(r, c);\
   2038               ctx->boolShift  = 5;\
   2039               ctx->boolOffset = (*r)->count -1
   2040               storeNew4bPackedBool(e->data);
   2041             }
   2042             else {
   2043               // high nibble, next byte is packed bools
   2044               storeTypeInHighNbl(e->data);
   2045               #define storeNew8bPackedBool(o)\
   2046               u8 c         = 0;\
   2047               if (((sBoolt *)(o))->value)\
   2048                 c = 1;\
   2049               sBytesPush(r, c);\
   2050               ctx->boolShift  = 1;\
   2051               ctx->boolOffset = (*r)->count -1
   2052               storeNew8bPackedBool(e->data);
   2053             }
   2054           }
   2055           else {
   2056             // there was a bool before this one, fill bits in nibbles
   2057             if (ctx->nibble == lowNbl) {
   2058               if (ctx->boolShift == 8) {
   2059                 // previous packed bool is full
   2060                 // this byte is the new packed bools
   2061                 storeNew4bPackedBool(e->data);
   2062               }
   2063               else {
   2064                 storeTypeOnly(e->data);
   2065                 #define storeBool(o)\
   2066                 data           = (char *)&((*r)->data) + ctx->boolOffset;\
   2067                 if (((sBoolt *)(o))->value)\
   2068                   *data |= 1 << ctx->boolShift;\
   2069                 ctx->boolShift++
   2070                 storeBool(e->data);
   2071               }
   2072             }
   2073             else {
   2074               // high nibble
   2075               storeTypeInHighNbl(e->data);
   2076               if (ctx->boolShift == 8) {
   2077                 // previous packed bool is full
   2078                 // next byte is the new packed bools
   2079                 storeNew8bPackedBool(e->data);
   2080               }
   2081               else {
   2082                 storeBool(e->data);
   2083               }
   2084             }
   2085           }
   2086           break;
   2087         case DICT:
   2088           if (pack) {
   2089             if (type) {
   2090               // this is the first packed element
   2091               if (ctx->nibble == lowNbl) {
   2092                 uintToNetTypeVarint(r, type, packCount);
   2093               }
   2094               else {
   2095                 // high nibble
   2096                 // store type in high nibble
   2097                 ctx->nibble  = lowNbl;
   2098                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2099                 *data       |= type << 4;
   2100                 uintToVarint(r, packCount);
   2101               }
   2102               type = 0;
   2103             } // if type
   2104 
   2105             dictNetSerial(r, (sDictt *)(e->data), ctx, /*packing=*/PACK);
   2106             // stop packing when packCount == 0
   2107             packCount--;
   2108             if (!packCount) pack = false;
   2109           } // if pack
   2110           else
   2111             dictNetSerial(r, (sDictt *)(e->data), ctx, /*packing=*/NOPACKING);
   2112           break;
   2113         case DOUBLE:
   2114           if (pack) {
   2115             if (type) {
   2116               // this is the first packed element
   2117               if (ctx->nibble == lowNbl) {
   2118                 uintToNetTypeVarint(r, type, packCount);
   2119               }
   2120               else {
   2121                 // high nibble
   2122                 // store type in high nibble
   2123                 ctx->nibble  = lowNbl;
   2124                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2125                 *data       |= type << 4;
   2126                 uintToVarint(r, packCount);
   2127               }
   2128               type = 0;
   2129             } // if type
   2130 
   2131             sBytesPushBuffer(r, &((sDoublet *)(e->data))->value, sizeof(double));
   2132             // stop packing when packCount == 0
   2133             packCount--;
   2134             if (!packCount) pack = false;
   2135           } // if pack
   2136           else {
   2137             if (ctx->nibble == lowNbl) {
   2138               storeTypeOnly(e->data);
   2139             }
   2140             else {
   2141               // high nibble
   2142               storeTypeInHighNbl(e->data);
   2143             }
   2144             sBytesPushBuffer(r, &((sDoublet *)(e->data))->value, sizeof(double));
   2145           }
   2146           break;
   2147         case INT:
   2148           if (pack) {
   2149             if (type) {
   2150               // this is the first packed element
   2151               if (ctx->nibble == lowNbl) {
   2152                 uintToNetTypeVarint(r, type, packCount);
   2153               }
   2154               else {
   2155                 // high nibble
   2156                 // store type in high nibble
   2157                 ctx->nibble  = lowNbl;
   2158                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2159                 *data       |= type << 4;
   2160                 uintToVarint(r, packCount);
   2161               }
   2162               type = 0;
   2163             } // if type
   2164 
   2165             i64 v = ((sIntt *)(e->data))->value;
   2166             uintToVarint(r, (v << 1) ^ (v >> 63));
   2167             // stop packing when packCount == 0
   2168             packCount--;
   2169             if (!packCount) pack = false;
   2170           } // if pack
   2171           else {
   2172             // encode int to varint
   2173             // v is int64_t to convert to varint
   2174             i64 v = ((sIntt *)(e->data))->value;
   2175             if (ctx->nibble == lowNbl) {
   2176               // encode v with arithmetic shifts
   2177               uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->data->type], (v << 1) ^ (v >> 63));
   2178             }
   2179             else {
   2180               // high nibble
   2181               storeTypeInHighNbl(e->data);
   2182               uintToVarint(r, (v << 1) ^ (v >> 63));
   2183             }
   2184           }
   2185           break;
   2186         case STRING:
   2187           if (pack) {
   2188             if (type) {
   2189               // this is the first packed element
   2190               if (ctx->nibble == lowNbl) {
   2191                 uintToNetTypeVarint(r, type, packCount);
   2192               }
   2193               else {
   2194                 // high nibble
   2195                 // store type in high nibble
   2196                 ctx->nibble  = lowNbl;
   2197                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2198                 *data       |= type << 4;
   2199                 uintToVarint(r, packCount);
   2200               }
   2201               type = 0;
   2202             } // if type
   2203 
   2204             sBytesPushBuffer(r, &((sStringt *)(e->data))->data, sizeof(sStringt) + strlen(&(((sStringt *)(e->data))->data)) -1);
   2205             // stop packing when packCount == 0
   2206             packCount--;
   2207             if (!packCount) pack = false;
   2208           } // if pack
   2209           else {
   2210             if (ctx->nibble == lowNbl) {
   2211               storeTypeOnly(e->data);
   2212             }
   2213             else {
   2214               // high nibble
   2215               storeTypeInHighNbl(e->data);
   2216             }
   2217             sBytesPushBuffer(r, &((sStringt *)(e->data))->data, sizeof(sStringt) + strlen(&(((sStringt *)(e->data))->data)) -1);
   2218           }
   2219           break;
   2220         case ARRAY:
   2221           if (pack) {
   2222             if (type) {
   2223               // this is the first packed element
   2224               if (ctx->nibble == lowNbl) {
   2225                 uintToNetTypeVarint(r, type, packCount);
   2226               }
   2227               else {
   2228                 // high nibble
   2229                 // store type in high nibble
   2230                 ctx->nibble  = lowNbl;
   2231                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2232                 *data       |= type << 4;
   2233                 uintToVarint(r, packCount);
   2234               }
   2235               type = 0;
   2236             } // if type
   2237 
   2238             arrayNetSerial(r, (sArrayt *)(e->data), ctx, /*packing=*/PACK);
   2239             // stop packing when packCount == 0
   2240             packCount--;
   2241             if (!packCount) pack = false;
   2242           } // if pack
   2243           else
   2244             arrayNetSerial(r, (sArrayt *)(e->data), ctx, /*packing=*/NOPACKING);
   2245           break;
   2246         case BYTES:
   2247           if (pack) {
   2248             if (type) {
   2249               // this is the first packed element
   2250               if (ctx->nibble == lowNbl) {
   2251                 uintToNetTypeVarint(r, type, packCount);
   2252               }
   2253               else {
   2254                 // high nibble
   2255                 // store type in high nibble
   2256                 ctx->nibble  = lowNbl;
   2257                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2258                 *data       |= type << 4;
   2259                 uintToVarint(r, packCount);
   2260               }
   2261               type = 0;
   2262             } // if type
   2263 
   2264             B = (sBytest *)(e->data);
   2265             uintToVarint(r, B->count);
   2266             sBytesPushBuffer(r, &(B->data), B->count);
   2267             // stop packing when packCount == 0
   2268             packCount--;
   2269             if (!packCount) pack = false;
   2270           } // if pack
   2271           else {
   2272             B = (sBytest *)(e->data);
   2273             if (ctx->nibble == lowNbl) {
   2274               uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->data->type], B->count);
   2275             }
   2276             else {
   2277               // high nibble
   2278               storeTypeInHighNbl(e->data);
   2279               uintToVarint(r, B->count);
   2280             }
   2281             sBytesPushBuffer(r, &(B->data), B->count);
   2282           }
   2283           break;
   2284       }
   2285     }
   2286   }
   2287   ret;
   2288 }
   2289 
   2290 /**
   2291  * serialize array
   2292  *
   2293  * the serialized array is pushed to r.
   2294  * All elements are serialized recursively
   2295  *
   2296  * the data in containers is not serialized
   2297  *
   2298  * \param
   2299  *   r small bytes object
   2300  *   array to serialize
   2301  */
   2302 internal void arrayNetSerial(sBytest **r, sArrayt *array, contextt *ctx, packingT packing) {
   2303   sBytest *B     = NULL;
   2304   char    *data  = NULL;
   2305 
   2306   // check if all elements have same type
   2307   // then set array type normal or uniform
   2308   // array and dict have to be checked recursively to know if they are normal or uniform
   2309   bool allElementsHaveSameType = true;
   2310   bool foundFirstType          = false;
   2311   char type                    = 0;
   2312 
   2313   // get first element type
   2314   // compare to other element type
   2315   // null element are interpreted as undefined
   2316   {forEachSArray(array, e) {
   2317     if (!e) {
   2318       if (foundFirstType) {
   2319         if (type != S_UNDEFINED) {
   2320           allElementsHaveSameType = false;
   2321           break;
   2322         }
   2323       }
   2324       else {
   2325         type = S_UNDEFINED;
   2326         foundFirstType = true;
   2327       }
   2328     }
   2329     else {
   2330       if (foundFirstType) {
   2331         u8 nextType;
   2332         switch(e->type) {
   2333           case DICT:
   2334             nextType = isDictUniform((sDictt*)e);
   2335             break;
   2336           case ARRAY:
   2337             nextType = isArrayUniform((sArrayt*)e);
   2338             break;
   2339           default:
   2340             nextType = NET_SERIAL_TYPES[(u8)e->type];
   2341         }
   2342         if (nextType != type) {
   2343           allElementsHaveSameType = false;
   2344           break;
   2345         }
   2346       }
   2347       else {
   2348         switch(e->type) {
   2349           case DICT:
   2350             type = isDictUniform((sDictt*)e);
   2351             break;
   2352           case ARRAY:
   2353             type = isArrayUniform((sArrayt*)e);
   2354             break;
   2355           default:
   2356             type = NET_SERIAL_TYPES[(u8)e->type];
   2357         }
   2358         foundFirstType = true;
   2359       }
   2360     }
   2361   }}
   2362 
   2363   if (allElementsHaveSameType) {
   2364     // uniform array
   2365     // encode type and element count
   2366 
   2367     // in pack array
   2368     if (packing == PACK) {
   2369       // uniform array can't be packed
   2370       // because there is only one type of packed arrays
   2371       goto normalArray;
   2372     }
   2373     elif (packing == UNIFORM) {
   2374       // when the packing is uniform, there is no need to encode UNIFORM_ARRAY since all elements have this type
   2375       uintToNetTypeVarint(r, type, array->count);
   2376     }
   2377     else {
   2378       if (ctx->nibble == lowNbl) {
   2379         sBytesPush(r, (type << 4) + UNIFORM_ARRAY);
   2380         uintToVarint(r, array->count);
   2381       }
   2382       else {
   2383         // high nibble
   2384         ctx->nibble  = lowNbl;
   2385         data         = (char *)&((*r)->data) + ctx->nblOffset;
   2386         *data       |= UNIFORM_ARRAY << 4;
   2387         uintToNetTypeVarint(r, type, array->count);
   2388       }
   2389     }
   2390 
   2391     // encode all element values
   2392     switch(type) {
   2393       case S_BOOL:
   2394         {forEachSArray(array, e) {
   2395           if (!ctx->boolOffset) {
   2396             // new packed bools
   2397             storeNew8bPackedBool(e);
   2398           }
   2399           else {
   2400             // there was a bool before this one, fill bits in nibbles
   2401             if (ctx->boolShift == 8) {
   2402               // previous packed bool is full
   2403               // next byte is the new packed bools
   2404               storeNew8bPackedBool(e);
   2405             }
   2406             else {
   2407               storeBool(e);
   2408             }
   2409           }
   2410         }}
   2411         break;
   2412       case S_DICT:
   2413       case UNIFORM_DICT:
   2414         {forEachSArray(array, e) {
   2415           dictNetSerial(r, (sDictt *)e, ctx, /*packing=*/UNIFORM);
   2416         }}
   2417         break;
   2418       case S_DOUBLE:
   2419         {forEachSArray(array, e) {
   2420           sBytesPushBuffer(r, &((sDoublet *)e)->value, sizeof(double));
   2421         }}
   2422         break;
   2423       case S_INT:
   2424         {forEachSArray(array, e) {
   2425           i64 v = ((sIntt *)e)->value;
   2426           uintToVarint(r, (v << 1) ^ (v >> 63));
   2427         }}
   2428         break;
   2429       case S_STRING:
   2430         {forEachSArray(array, e) {
   2431           sBytesPushBuffer(r, &((sStringt *)e)->data, sizeof(sStringt) + strlen(&(((sStringt *)e)->data)) -1);
   2432         }}
   2433         break;
   2434       case S_ARRAY:
   2435       case UNIFORM_ARRAY:
   2436         {forEachSArray(array, e) {
   2437           arrayNetSerial(r, (sArrayt *)e, ctx, /*packing=*/UNIFORM);
   2438         }}
   2439         break;
   2440       case S_BYTES:
   2441         {forEachSArray(array, e) {
   2442           B = (sBytest *)e;
   2443           uintToVarint(r, B->count);
   2444           sBytesPushBuffer(r, &(B->data), B->count);
   2445         }}
   2446         break;
   2447     }
   2448     ret;
   2449   }
   2450 
   2451   normalArray:
   2452   // encode type and element count
   2453   if (packing == PACK or packing == UNIFORM) {
   2454     // when the packing is packed or uniform, there is no need to encode ARRAY type since all elements have this type
   2455     uintToVarint(r, array->count);
   2456   }
   2457   else {
   2458     if (ctx->nibble == lowNbl) {
   2459       uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)array->type], array->count);
   2460     }
   2461     else {
   2462       // high nibble
   2463       storeTypeInHighNbl(array);
   2464       uintToVarint(r, array->count);
   2465     }
   2466   }
   2467 
   2468   bool   pack = false;
   2469   size_t packCount;
   2470   enumerateSArray(array, e, eIdx) {
   2471     if (!e) {
   2472       // empty slots are represented as undefined elements
   2473       if (ctx->nibble == lowNbl) {
   2474         sBytesPush(r, NET_SERIAL_TYPES[UNDEFINED]);
   2475         ctx->nibble    = highNbl;
   2476         ctx->nblOffset = (*r)->count -1;
   2477       }
   2478       else {
   2479         // high nibble
   2480         ctx->nibble  = lowNbl;
   2481         data         = (char *)&((*r)->data) + ctx->nblOffset;
   2482         *data       |= NET_SERIAL_TYPES[UNDEFINED] << 4;
   2483       }
   2484     }
   2485     else {
   2486       if (!pack) {
   2487         // scan array for packing
   2488         if ((array->count - eIdx) > 3) {
   2489           // at least 4 elements, less than that is not worth it
   2490           if (   e->type == DICT
   2491               or e->type == DOUBLE
   2492               or e->type == INT
   2493               or e->type == STRING
   2494               or e->type == ARRAY
   2495               or e->type == BYTES) {
   2496             type      = e->type;
   2497             packCount = 1;
   2498             smallt *element = ((smallt **) &((array)->data))[eIdx+1];
   2499             for (size_t i = eIdx+1; i < (array)->count ; i++, element = ((smallt **) &((array)->data))[i]) {
   2500               if (!element) {
   2501                 // null element are undefined
   2502                 break;
   2503               }
   2504               else {
   2505                 if (element->type != type) {
   2506                   break;
   2507                 }
   2508                 packCount++;
   2509               } // if element
   2510             } // for
   2511             if (packCount > 3) {
   2512               type = PACKED_NET_SERIAL_TYPES[(u8)type];
   2513               pack = true;
   2514             }
   2515           } // test current element type
   2516         } // is array big enough
   2517       } // not already packing
   2518 
   2519       // encode element value
   2520       switch(e->type) {
   2521         case UNDEFINED:
   2522         case CONTAINER:
   2523           if (ctx->nibble == lowNbl) {
   2524             storeTypeOnly(e);
   2525           }
   2526           else {
   2527             // high nibble
   2528             storeTypeInHighNbl(e);
   2529           }
   2530           break;
   2531         case BOOL:
   2532           if (!ctx->boolOffset) {
   2533             // new packed bools
   2534             if (ctx->nibble == lowNbl) {
   2535               storeNew4bPackedBool(e);
   2536             }
   2537             else {
   2538               // high nibble, next byte is packed bools
   2539               storeTypeInHighNbl(e);
   2540               storeNew8bPackedBool(e);
   2541             }
   2542           }
   2543           else {
   2544             // there was a bool before this one, fill bits in nibbles
   2545             if (ctx->nibble == lowNbl) {
   2546               if (ctx->boolShift == 8) {
   2547                 // previous packed bool is full
   2548                 // this byte is the new packed bools
   2549                 storeNew4bPackedBool(e);
   2550               }
   2551               else {
   2552                 storeTypeOnly(e);
   2553                 storeBool(e);
   2554               }
   2555             }
   2556             else {
   2557               // high nibble
   2558               storeTypeInHighNbl(e);
   2559               if (ctx->boolShift == 8) {
   2560                 // previous packed bool is full
   2561                 // next byte is the new packed bools
   2562                 storeNew8bPackedBool(e);
   2563               }
   2564               else {
   2565                 storeBool(e);
   2566               }
   2567             }
   2568           }
   2569           break;
   2570         case DICT:
   2571           if (pack) {
   2572             if (type) {
   2573               // this is the first packed element
   2574               if (ctx->nibble == lowNbl) {
   2575                 uintToNetTypeVarint(r, type, packCount);
   2576               }
   2577               else {
   2578                 // high nibble
   2579                 // store type in high nibble
   2580                 ctx->nibble  = lowNbl;
   2581                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2582                 *data       |= type << 4;
   2583                 uintToVarint(r, packCount);
   2584               }
   2585               type = 0;
   2586             } // if type
   2587 
   2588             dictNetSerial(r, (sDictt *)e, ctx, /*packing=*/PACK);
   2589             // stop packing when packCount == 0
   2590             packCount--;
   2591             if (!packCount) pack = false;
   2592           } // if pack
   2593           else
   2594             dictNetSerial(r, (sDictt *)e, ctx, /*packing=*/NOPACKING);
   2595           break;
   2596         case DOUBLE:
   2597           if (pack) {
   2598             if (type) {
   2599               // this is the first packed element
   2600               if (ctx->nibble == lowNbl) {
   2601                 uintToNetTypeVarint(r, type, packCount);
   2602               }
   2603               else {
   2604                 // high nibble
   2605                 // store type in high nibble
   2606                 ctx->nibble  = lowNbl;
   2607                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2608                 *data       |= type << 4;
   2609                 uintToVarint(r, packCount);
   2610               }
   2611               type = 0;
   2612             } // if type
   2613 
   2614             sBytesPushBuffer(r, &((sDoublet *)e)->value, sizeof(double));
   2615             // stop packing when packCount == 0
   2616             packCount--;
   2617             if (!packCount) pack = false;
   2618           } // if pack
   2619           else {
   2620             if (ctx->nibble == lowNbl) {
   2621               storeTypeOnly(e);
   2622             }
   2623             else {
   2624               // high nibble
   2625               storeTypeInHighNbl(e);
   2626             }
   2627             sBytesPushBuffer(r, &((sDoublet *)e)->value, sizeof(double));
   2628           }
   2629           break;
   2630         case INT:
   2631           if (pack) {
   2632             if (type) {
   2633               // this is the first packed element
   2634               if (ctx->nibble == lowNbl) {
   2635                 uintToNetTypeVarint(r, type, packCount);
   2636               }
   2637               else {
   2638                 // high nibble
   2639                 // store type in high nibble
   2640                 ctx->nibble  = lowNbl;
   2641                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2642                 *data       |= type << 4;
   2643                 uintToVarint(r, packCount);
   2644               }
   2645               type = 0;
   2646             } // if type
   2647 
   2648             i64 v = ((sIntt *)&(e->type))->value;
   2649             uintToVarint(r, (v << 1) ^ (v >> 63));
   2650             // stop packing when packCount == 0
   2651             packCount--;
   2652             if (!packCount) pack = false;
   2653           } // if pack
   2654           else {
   2655             // encode int to varint
   2656             // v is int64_t to convert to varint
   2657             i64 v = ((sIntt *)&(e->type))->value;
   2658             if (ctx->nibble == lowNbl) {
   2659               // encode v with arithmetic shifts
   2660               uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->type], (v << 1) ^ (v >> 63));
   2661             }
   2662             else {
   2663               // high nibble
   2664               storeTypeInHighNbl(e);
   2665               uintToVarint(r, (v << 1) ^ (v >> 63));
   2666             }
   2667           }
   2668           break;
   2669         case STRING:
   2670           if (pack) {
   2671             if (type) {
   2672               // this is the first packed element
   2673               if (ctx->nibble == lowNbl) {
   2674                 uintToNetTypeVarint(r, type, packCount);
   2675               }
   2676               else {
   2677                 // high nibble
   2678                 // store type in high nibble
   2679                 ctx->nibble  = lowNbl;
   2680                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2681                 *data       |= type << 4;
   2682                 uintToVarint(r, packCount);
   2683               }
   2684               type = 0;
   2685             } // if type
   2686 
   2687             sBytesPushBuffer(r, &((sStringt *)e)->data, sizeof(sStringt) + strlen(&(((sStringt *)e)->data)) -1);
   2688             // stop packing when packCount == 0
   2689             packCount--;
   2690             if (!packCount) pack = false;
   2691           } // if pack
   2692           else {
   2693             if (ctx->nibble == lowNbl) {
   2694               storeTypeOnly(e);
   2695             }
   2696             else {
   2697               // high nibble
   2698               storeTypeInHighNbl(e);
   2699             }
   2700             sBytesPushBuffer(r, &((sStringt *)e)->data, sizeof(sStringt) + strlen(&(((sStringt *)e)->data)) -1);
   2701           }
   2702           break;
   2703         case ARRAY:
   2704           if (pack) {
   2705             if (type) {
   2706               // this is the first packed element
   2707               if (ctx->nibble == lowNbl) {
   2708                 uintToNetTypeVarint(r, type, packCount);
   2709               }
   2710               else {
   2711                 // high nibble
   2712                 // store type in high nibble
   2713                 ctx->nibble  = lowNbl;
   2714                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2715                 *data       |= type << 4;
   2716                 uintToVarint(r, packCount);
   2717               }
   2718               type = 0;
   2719             } // if type
   2720 
   2721             arrayNetSerial(r, (sArrayt *)e, ctx, /*packing=*/PACK);
   2722             // stop packing when packCount == 0
   2723             packCount--;
   2724             if (!packCount) pack = false;
   2725           } // if pack
   2726           else
   2727             arrayNetSerial(r, (sArrayt *)e, ctx, /*packing=*/NOPACKING);
   2728           break;
   2729         case BYTES:
   2730           if (pack) {
   2731             if (type) {
   2732               // this is the first packed element
   2733               if (ctx->nibble == lowNbl) {
   2734                 uintToNetTypeVarint(r, type, packCount);
   2735               }
   2736               else {
   2737                 // high nibble
   2738                 // store type in high nibble
   2739                 ctx->nibble  = lowNbl;
   2740                 data         = (char *)&((*r)->data) + ctx->nblOffset;
   2741                 *data       |= type << 4;
   2742                 uintToVarint(r, packCount);
   2743               }
   2744               type = 0;
   2745             } // if type
   2746 
   2747             B = (sBytest *)e;
   2748             uintToVarint(r, B->count);
   2749             sBytesPushBuffer(r, &(B->data), B->count);
   2750             // stop packing when packCount == 0
   2751             packCount--;
   2752             if (!packCount) pack = false;
   2753           } // if pack
   2754           else {
   2755             B = (sBytest *)e;
   2756             if (ctx->nibble == lowNbl) {
   2757               uintToNetTypeVarint(r, NET_SERIAL_TYPES[(u8)e->type], B->count);
   2758             }
   2759             else {
   2760               // high nibble
   2761               storeTypeInHighNbl(e);
   2762               uintToVarint(r, B->count);
   2763             }
   2764             sBytesPushBuffer(r, &(B->data), B->count);
   2765           }
   2766           break;
   2767       }
   2768     }
   2769   }
   2770   ret;
   2771 }
   2772 
   2773 internal smallBytest* serialNetSerial(smallJsont *self) {
   2774 
   2775   smallt *o = getsoG(self);
   2776 
   2777   if (o == NULL)
   2778     ret NULL;
   2779 
   2780   sBytest *B = netSerial(o);
   2781 
   2782   if (!B) {
   2783     ret NULL;
   2784   }
   2785 
   2786   createAllocateSmallBytes(r);
   2787   r->B = B;
   2788   ret r;
   2789 }
   2790 
   2791 // -------------------------------------
   2792 // Deserializers
   2793 
   2794 // level 0
   2795 // like smallJson with ints and length encoded as varints
   2796 
   2797 /**
   2798  * deserializer top function
   2799  */
   2800 internal smallt* netDeserialLevel0(sBytest *obj) {
   2801   smallt   *r = NULL;
   2802   double   *D = NULL;
   2803   char     *s = NULL;
   2804   sBytest  *B = NULL;
   2805   uint32_t count;
   2806   char     *data  = NULL;
   2807 
   2808   switch(obj->data & 0xF) {
   2809     case S_UNDEFINED:
   2810       r = (smallt *) allocSUndefined();
   2811       break;
   2812     case S_BOOL:
   2813       r = (smallt *) allocSBool(obj->data & 0x10);
   2814       break;
   2815     case S_DICT:
   2816       data = (char *)&(obj->data);
   2817       dictNetDeserialLevel0((sDictt **)&r, &data);
   2818       break;
   2819     case S_DOUBLE:
   2820       data = &(obj->data)+1;
   2821       D = (double *)data;
   2822       r = (smallt *) allocSDouble(*D);
   2823       break;
   2824     case S_INT:
   2825       data  = &(obj->data);
   2826       u64 v = netTypeVarintToUint((u8**)&data);
   2827       v = (v >> 1) ^ (~(v & 1) + 1);
   2828       r = (smallt *) allocSInt(v);
   2829       break;
   2830     case S_STRING:
   2831       s = (char *)&(obj->data)+1;
   2832       r = (smallt *) allocSStringTiny(s);
   2833       break;
   2834     case S_ARRAY:
   2835       data = (char *)&(obj->data);
   2836       arrayNetDeserialLevel0((sArrayt **)&r, &data);
   2837       break;
   2838     case S_BYTES:
   2839       B     = allocSBytes();
   2840       data  = &(obj->data);
   2841       count = netTypeVarintToUint((u8**)&data);
   2842       sBytesPushBuffer(&B, data, count);
   2843       r = (smallt *)B;
   2844       break;
   2845   }
   2846 
   2847   ret r;
   2848 }
   2849 
   2850 /**
   2851  * deserialize dictionary from data
   2852  *
   2853  * a new dictionary is allocated
   2854  *
   2855  * \param
   2856  *    dict dictionary holding the elements
   2857  *    data serialized dictionary
   2858  */
   2859 internal void dictNetDeserialLevel0(sDictt **dict, char **data) {
   2860   sUndefinedt *u = NULL;
   2861   sBoolt *bo = NULL;
   2862   double *D = NULL;
   2863   sDoublet *Do = NULL;
   2864   sDictt *d = NULL;
   2865   sIntt *io = NULL;
   2866   char *s = NULL;
   2867   sStringt *so = NULL;
   2868   sArrayt *a = NULL;
   2869   sBytest *B = NULL;
   2870   uint32_t count;
   2871   uint32_t dictCount;
   2872 
   2873   dictCount = netTypeVarintToUint((u8**)data);
   2874 
   2875   if (!dictCount) {
   2876     *dict = allocSDict();
   2877     ret;
   2878   }
   2879 
   2880   loop(dictCount) {
   2881     char type;
   2882     char *key;
   2883     key    = *data;
   2884     *data += strlen(key)+1;
   2885     type   = **data;
   2886 
   2887     switch(type & 0xF) {
   2888       case S_UNDEFINED:
   2889         (*data)++;
   2890         u    = allocSUndefined();
   2891         sDictPushTiny(dict, key, (smallt *) u);
   2892         break;
   2893       case S_BOOL:
   2894         (*data)++;
   2895         bo = allocSBool(type & 0x10);
   2896         sDictPushTiny(dict, key, (smallt *) bo);
   2897         break;
   2898       case S_DICT:
   2899         d = NULL;
   2900         dictNetDeserialLevel0(&d, data);
   2901         sDictPushTiny(dict, key, (smallt *) d);
   2902         break;
   2903       case S_DOUBLE:
   2904         (*data)++;
   2905         D      = (double *)(*data);
   2906         *data += sizeof(double);
   2907         Do     = allocSDouble(*D);
   2908         sDictPushTiny(dict, key, (smallt *) Do);
   2909         break;
   2910       case S_INT: {
   2911           u64 v = netTypeVarintToUint((u8**)data);
   2912           v = (v >> 1) ^ (~(v & 1) + 1);
   2913           io     = allocSInt(v);
   2914           sDictPushTiny(dict, key, (smallt *) io);
   2915         }
   2916         break;
   2917       case S_STRING:
   2918         (*data)++;
   2919         s      = (char *)(*data);
   2920         *data += strlen(s)+1;
   2921         so     = allocSStringTiny(s);
   2922         sDictPushTiny(dict, key, (smallt *) so);
   2923         break;
   2924       case S_ARRAY:
   2925         a = NULL;
   2926         arrayNetDeserialLevel0(&a, data);
   2927         sDictPushTiny(dict, key, (smallt *) a);
   2928         break;
   2929       case S_BYTES:
   2930         B      = allocSBytes();
   2931         count  = netTypeVarintToUint((u8**)data);
   2932         sBytesPushBuffer(&B, *data, count);
   2933         *data += count;
   2934         sDictPushTiny(dict, key, (smallt *) B);
   2935         break;
   2936     }
   2937   }
   2938 }
   2939 
   2940 /**
   2941  * deserialize array from data
   2942  *
   2943  * a new array is allocated
   2944  *
   2945  * \param
   2946  *    array holding the elements
   2947  *    data serialized dictionary
   2948  */
   2949 internal void arrayNetDeserialLevel0(sArrayt **array, char **data) {
   2950   sUndefinedt *u = NULL;
   2951   sBoolt *bo = NULL;
   2952   double *D = NULL;
   2953   sDoublet *Do = NULL;
   2954   sDictt *d = NULL;
   2955   sIntt *io = NULL;
   2956   char *s = NULL;
   2957   sStringt *so = NULL;
   2958   sArrayt *a = NULL;
   2959   sBytest *B = NULL;
   2960   uint32_t count;
   2961   uint32_t arrayCount;
   2962 
   2963   arrayCount = netTypeVarintToUint((u8**)data);
   2964 
   2965   if (!arrayCount) {
   2966     *array = allocSArray();;
   2967     ret;
   2968   }
   2969 
   2970   loop(arrayCount) {
   2971     char type;
   2972     type  = **data;
   2973 
   2974     switch(type & 0xF) {
   2975       case S_UNDEFINED:
   2976         (*data)++;
   2977         u = allocSUndefined();
   2978         sArrayPushTiny(array, (smallt *) u);
   2979         break;
   2980       case S_BOOL:
   2981         (*data)++;
   2982         bo     = allocSBool(type & 0x10);
   2983         sArrayPushTiny(array, (smallt *) bo);
   2984         break;
   2985       case S_DICT:
   2986         d = NULL;
   2987         dictNetDeserialLevel0(&d, data);
   2988         sArrayPushTiny(array, (smallt *) d);
   2989         break;
   2990       case S_DOUBLE:
   2991         (*data)++;
   2992         D      = (double *)(*data);
   2993         *data += sizeof(double);
   2994         Do     = allocSDouble(*D);
   2995         sArrayPushTiny(array, (smallt *) Do);
   2996         break;
   2997       case S_INT: {
   2998           u64 v = netTypeVarintToUint((u8**)data);
   2999           v = (v >> 1) ^ (~(v & 1) + 1);
   3000           io     = allocSInt(v);
   3001           sArrayPushTiny(array, (smallt *) io);
   3002         }
   3003         break;
   3004       case S_STRING:
   3005         (*data)++;
   3006         s      = (char *)(*data);
   3007         *data += strlen(s)+1;
   3008         so     = allocSStringTiny(s);
   3009         sArrayPushTiny(array, (smallt *) so);
   3010         break;
   3011       case S_ARRAY:
   3012         a = NULL;
   3013         arrayNetDeserialLevel0(&a, data);
   3014         sArrayPushTiny(array, (smallt *) a);
   3015         break;
   3016       case S_BYTES:
   3017         B      = allocSBytes();
   3018         count  = netTypeVarintToUint((u8**)data);
   3019         sBytesPushBuffer(&B, *data, count);
   3020         *data += count;
   3021         sArrayPushTiny(array, (smallt *) B);
   3022         break;
   3023     }
   3024   }
   3025 }
   3026 
   3027 internal smallJsont* deserialNetSerialLevel0(smallJsont *self, smallBytest *data) {
   3028 
   3029   if (!data or !data->B or !data->B->count) {
   3030     ret self;
   3031   }
   3032 
   3033   smallt *o = netDeserialLevel0(data->B);
   3034 
   3035   if (!o) {
   3036     ret self;
   3037   }
   3038 
   3039   freeG(self);
   3040 
   3041   setsoG(self, o);
   3042 
   3043   ret self;
   3044 }
   3045 
   3046 // level 1
   3047 // like level 0 with type encoded in nibbles and bools are packed
   3048 
   3049 /**
   3050  * deserializer top function
   3051  */
   3052 internal smallt* netDeserialLevel1(sBytest *obj) {
   3053   smallt   *r = NULL;
   3054   double   *D = NULL;
   3055   char     *s = NULL;
   3056   sBytest  *B = NULL;
   3057   uint32_t count;
   3058   char     *data  = NULL;
   3059   contextt ctx = {.nibble=lowNbl, .nblAddr=NULL, .boolShift = 0, .boolAddr=NULL};
   3060 
   3061   switch(obj->data & 0xF) {
   3062     case S_UNDEFINED:
   3063       r = (smallt *) allocSUndefined();
   3064       break;
   3065     case S_BOOL:
   3066       r = (smallt *) allocSBool(obj->data & 0x10);
   3067       break;
   3068     case S_DICT:
   3069       data     = (char *)&(obj->data);
   3070       //debug - ctx.dbuf = (u8*) data;
   3071       dictNetDeserialLevel1((sDictt **)&r, (u8**)&data, &ctx);
   3072       break;
   3073     case S_DOUBLE:
   3074       data = &(obj->data)+1;
   3075       D = (double *)data;
   3076       r = (smallt *) allocSDouble(*D);
   3077       break;
   3078     case S_INT:
   3079       data  = &(obj->data);
   3080       u64 v = netTypeVarintToUint((u8**)&data);
   3081       v = (v >> 1) ^ (~(v & 1) + 1);
   3082       r = (smallt *) allocSInt(v);
   3083       break;
   3084     case S_STRING:
   3085       s = (char *)&(obj->data)+1;
   3086       r = (smallt *) allocSStringTiny(s);
   3087       break;
   3088     case S_ARRAY:
   3089       data = (char *)&(obj->data);
   3090       //debug - ctx.dbuf = (u8*) data;
   3091       arrayNetDeserialLevel1((sArrayt **)&r, (u8**)&data, &ctx);
   3092       break;
   3093     case S_BYTES:
   3094       B     = allocSBytes();
   3095       data  = &(obj->data);
   3096       count = netTypeVarintToUint((u8**)&data);
   3097       sBytesPushBuffer(&B, data, count);
   3098       r = (smallt *)B;
   3099       break;
   3100   }
   3101 
   3102   ret r;
   3103 }
   3104 
   3105 /**
   3106  * deserialize dictionary from data
   3107  *
   3108  * a new dictionary is allocated
   3109  *
   3110  * \param
   3111  *    dict dictionary holding the elements
   3112  *    data serialized dictionary
   3113  */
   3114 internal void dictNetDeserialLevel1(sDictt **dict, u8 **data, contextt *ctx) {
   3115   sUndefinedt *u = NULL;
   3116   sBoolt *bo = NULL;
   3117   double *D = NULL;
   3118   sDoublet *Do = NULL;
   3119   sDictt *d = NULL;
   3120   sIntt *io = NULL;
   3121   char *s = NULL;
   3122   sStringt *so = NULL;
   3123   sArrayt *a = NULL;
   3124   sBytest *B = NULL;
   3125   uint32_t count;
   3126   uint32_t dictCount;
   3127 
   3128   if (ctx->nibble == lowNbl) {
   3129     dictCount = netTypeVarintToUint(data);
   3130   }
   3131   else {
   3132     // high nibble
   3133     // type = *(ctx->dbuf + ctx->nblOffset) >> 4;
   3134     #define readTypeInHighNbl\
   3135     ctx->nibble  = lowNbl;\
   3136     if (ctx->nblAddr == *data)\
   3137       /* data points to the type, next byte is count */\
   3138       (*data)++
   3139     readTypeInHighNbl;
   3140     dictCount = varintToUint(data);
   3141   }
   3142 
   3143   if (!dictCount) {
   3144     *dict = allocSDict();
   3145     ret;
   3146   }
   3147 
   3148   loop(dictCount) {
   3149     char *key  = (char*)*data;
   3150     *data     += strlen(key)+1;
   3151     char type;
   3152     if (ctx->nibble == lowNbl) {
   3153       type = (**data) & 0xF;
   3154     }
   3155     else {
   3156       // high nibble
   3157       type = (*ctx->nblAddr) >> 4;
   3158     }
   3159 
   3160     switch(type) {
   3161       case S_UNDEFINED:
   3162         if (ctx->nibble == lowNbl) {
   3163           #define readTypeOnly\
   3164           ctx->nibble  = highNbl;\
   3165           ctx->nblAddr = *data;\
   3166           (*data)++
   3167           readTypeOnly;
   3168         }
   3169         else {
   3170           // high nibble
   3171           readTypeInHighNbl;
   3172         }
   3173         u = allocSUndefined();
   3174         sDictPushTiny(dict, key, (smallt *) u);
   3175         break;
   3176       case S_BOOL:
   3177         if (!ctx->boolAddr) {
   3178           // new packed bools
   3179           if (ctx->nibble == lowNbl) {
   3180             #define read4bPackedBool\
   3181             ctx->boolShift  = 5;\
   3182             ctx->boolAddr   = *data;\
   3183             (*data)++
   3184             read4bPackedBool;
   3185             bo = allocSBool((*ctx->boolAddr) & 0x10);
   3186           }
   3187           else {
   3188             // high nibble
   3189             readTypeInHighNbl;
   3190             #define read8bPackedBool\
   3191             ctx->boolShift  = 1;\
   3192             ctx->boolAddr   = *data;\
   3193             (*data)++
   3194             read8bPackedBool;
   3195             bo = allocSBool((*ctx->boolAddr) & 0x1);
   3196           }
   3197         }
   3198         else {
   3199           // there was a bool before this one, read bits in nibbles
   3200           if (ctx->nibble == lowNbl) {
   3201             if (ctx->boolShift == 8) {
   3202               read4bPackedBool;
   3203               bo = allocSBool((*ctx->boolAddr) & 0x10);
   3204             }
   3205             else {
   3206               readTypeOnly;
   3207               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   3208             }
   3209           }
   3210           else {
   3211             // high nibble
   3212             readTypeInHighNbl;
   3213             if (ctx->boolShift == 8) {
   3214               read8bPackedBool;
   3215               bo = allocSBool((*ctx->boolAddr) & 0x1);
   3216             }
   3217             else {
   3218               // high nibble
   3219               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   3220             }
   3221           }
   3222         }
   3223         sDictPushTiny(dict, key, (smallt *) bo);
   3224         break;
   3225       case S_DICT:
   3226         d = NULL;
   3227         dictNetDeserialLevel1(&d, data, ctx);
   3228         sDictPushTiny(dict, key, (smallt *) d);
   3229         break;
   3230       case S_DOUBLE:
   3231         if (ctx->nibble == lowNbl) {
   3232           readTypeOnly;
   3233         }
   3234         else {
   3235           // high nibble
   3236           readTypeInHighNbl;
   3237         }
   3238         D      = (double *)(*data);
   3239         *data += sizeof(double);
   3240         Do     = allocSDouble(*D);
   3241         sDictPushTiny(dict, key, (smallt *) Do);
   3242         break;
   3243       case S_INT: {
   3244           u64 v;
   3245           if (ctx->nibble == lowNbl) {
   3246             v = netTypeVarintToUint((u8**)data);
   3247           }
   3248           else {
   3249             // high nibble
   3250             readTypeInHighNbl;
   3251             v = varintToUint(data);
   3252           }
   3253           v  = (v >> 1) ^ (~(v & 1) + 1);
   3254           io = allocSInt(v);
   3255           sDictPushTiny(dict, key, (smallt *) io);
   3256         }
   3257         break;
   3258       case S_STRING:
   3259         if (ctx->nibble == lowNbl) {
   3260           readTypeOnly;
   3261         }
   3262         else {
   3263           // high nibble
   3264           readTypeInHighNbl;
   3265         }
   3266         s      = (char *)(*data);
   3267         *data += strlen(s)+1;
   3268         so     = allocSStringTiny(s);
   3269         sDictPushTiny(dict, key, (smallt *) so);
   3270         break;
   3271       case S_ARRAY:
   3272         a = NULL;
   3273         arrayNetDeserialLevel1(&a, data, ctx);
   3274         sDictPushTiny(dict, key, (smallt *) a);
   3275         break;
   3276       case S_BYTES:
   3277         B      = allocSBytes();
   3278         if (ctx->nibble == lowNbl) {
   3279           count  = netTypeVarintToUint((u8**)data);
   3280         }
   3281         else {
   3282           // high nibble
   3283           readTypeInHighNbl;
   3284           count  = varintToUint((u8**)data);
   3285         }
   3286         sBytesPushBuffer(&B, *data, count);
   3287         *data += count;
   3288         sDictPushTiny(dict, key, (smallt *) B);
   3289         break;
   3290     }
   3291   }
   3292 }
   3293 
   3294 /**
   3295  * deserialize array from data
   3296  *
   3297  * a new array is allocated
   3298  *
   3299  * \param
   3300  *    array holding the elements
   3301  *    data serialized dictionary
   3302  */
   3303 internal void arrayNetDeserialLevel1(sArrayt **array, u8 **data, contextt *ctx) {
   3304   sUndefinedt *u = NULL;
   3305   sBoolt *bo = NULL;
   3306   double *D = NULL;
   3307   sDoublet *Do = NULL;
   3308   sDictt *d = NULL;
   3309   sIntt *io = NULL;
   3310   char *s = NULL;
   3311   sStringt *so = NULL;
   3312   sArrayt *a = NULL;
   3313   sBytest *B = NULL;
   3314   uint32_t count;
   3315   uint32_t arrayCount;
   3316 
   3317   if (ctx->nibble == lowNbl) {
   3318     arrayCount = netTypeVarintToUint(data);
   3319   }
   3320   else {
   3321     // high nibble
   3322     readTypeInHighNbl;
   3323     arrayCount = varintToUint(data);
   3324   }
   3325 
   3326   if (!arrayCount) {
   3327     *array = allocSArray();;
   3328     ret;
   3329   }
   3330 
   3331   loop(arrayCount) {
   3332     char type;
   3333     if (ctx->nibble == lowNbl) {
   3334       type = (**data) & 0xF;
   3335     }
   3336     else {
   3337       // high nibble
   3338       type = (*ctx->nblAddr) >> 4;
   3339     }
   3340 
   3341     switch(type) {
   3342       case S_UNDEFINED:
   3343         if (ctx->nibble == lowNbl) {
   3344           readTypeOnly;
   3345         }
   3346         else {
   3347           // high nibble
   3348           readTypeInHighNbl;
   3349         }
   3350         u = allocSUndefined();
   3351         sArrayPushTiny(array, (smallt *) u);
   3352         break;
   3353       case S_BOOL:
   3354         if (!ctx->boolAddr) {
   3355           // new packed bools
   3356           if (ctx->nibble == lowNbl) {
   3357             read4bPackedBool;
   3358             bo = allocSBool((*ctx->boolAddr) & 0x10);
   3359           }
   3360           else {
   3361             // high nibble
   3362             readTypeInHighNbl;
   3363             read8bPackedBool;
   3364             bo = allocSBool((*ctx->boolAddr) & 0x1);
   3365           }
   3366         }
   3367         else {
   3368           // there was a bool before this one, read bits in nibbles
   3369           if (ctx->nibble == lowNbl) {
   3370             if (ctx->boolShift == 8) {
   3371               read4bPackedBool;
   3372               bo = allocSBool((*ctx->boolAddr) & 0x10);
   3373             }
   3374             else {
   3375               readTypeOnly;
   3376               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   3377             }
   3378           }
   3379           else {
   3380             // high nibble
   3381             readTypeInHighNbl;
   3382             if (ctx->boolShift == 8) {
   3383               read8bPackedBool;
   3384               bo = allocSBool((*ctx->boolAddr) & 0x1);
   3385             }
   3386             else {
   3387               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   3388             }
   3389           }
   3390         }
   3391         sArrayPushTiny(array, (smallt *) bo);
   3392         break;
   3393       case S_DICT:
   3394         d = NULL;
   3395         dictNetDeserialLevel1(&d, data, ctx);
   3396         sArrayPushTiny(array, (smallt *) d);
   3397         break;
   3398       case S_DOUBLE:
   3399         if (ctx->nibble == lowNbl) {
   3400           readTypeOnly;
   3401         }
   3402         else {
   3403           // high nibble
   3404           readTypeInHighNbl;
   3405         }
   3406         D      = (double *)(*data);
   3407         *data += sizeof(double);
   3408         Do     = allocSDouble(*D);
   3409         sArrayPushTiny(array, (smallt *) Do);
   3410         break;
   3411       case S_INT: {
   3412           u64 v;
   3413           if (ctx->nibble == lowNbl) {
   3414             v = netTypeVarintToUint((u8**)data);
   3415           }
   3416           else {
   3417             // high nibble
   3418             readTypeInHighNbl;
   3419             v = varintToUint(data);
   3420           }
   3421           v  = (v >> 1) ^ (~(v & 1) + 1);
   3422           io = allocSInt(v);
   3423           sArrayPushTiny(array, (smallt *) io);
   3424         }
   3425         break;
   3426       case S_STRING:
   3427         if (ctx->nibble == lowNbl) {
   3428           readTypeOnly;
   3429         }
   3430         else {
   3431           // high nibble
   3432           readTypeInHighNbl;
   3433         }
   3434         s      = (char *)(*data);
   3435         *data += strlen(s)+1;
   3436         so     = allocSStringTiny(s);
   3437         sArrayPushTiny(array, (smallt *) so);
   3438         break;
   3439       case S_ARRAY:
   3440         a = NULL;
   3441         arrayNetDeserialLevel1(&a, data, ctx);
   3442         sArrayPushTiny(array, (smallt *) a);
   3443         break;
   3444       case S_BYTES:
   3445         B      = allocSBytes();
   3446         if (ctx->nibble == lowNbl) {
   3447           count  = netTypeVarintToUint((u8**)data);
   3448         }
   3449         else {
   3450           // high nibble
   3451           readTypeInHighNbl;
   3452           count  = varintToUint((u8**)data);
   3453         }
   3454         sBytesPushBuffer(&B, *data, count);
   3455         *data += count;
   3456         sArrayPushTiny(array, (smallt *) B);
   3457         break;
   3458     }
   3459   }
   3460 }
   3461 
   3462 internal smallJsont* deserialNetSerialLevel1(smallJsont *self, smallBytest *data) {
   3463 
   3464   if (!data or !data->B or !data->B->count) {
   3465     ret self;
   3466   }
   3467 
   3468   smallt *o = netDeserialLevel1(data->B);
   3469 
   3470   if (!o) {
   3471     ret self;
   3472   }
   3473 
   3474   freeG(self);
   3475 
   3476   setsoG(self, o);
   3477 
   3478   ret self;
   3479 }
   3480 
   3481 // level 2
   3482 // like level 1, arrays are set to uniform when all elements are same type
   3483 
   3484 /**
   3485  * deserializer top function
   3486  */
   3487 internal smallt* netDeserialLevel2(sBytest *obj) {
   3488   smallt   *r = NULL;
   3489   double   *D = NULL;
   3490   char     *s = NULL;
   3491   sBytest  *B = NULL;
   3492   uint32_t count;
   3493   char     *data  = NULL;
   3494   contextt ctx = {.nibble=lowNbl, .nblAddr=NULL, .boolShift = 0, .boolAddr=NULL};
   3495 
   3496   switch(obj->data & 0xF) {
   3497     case S_UNDEFINED:
   3498       r = (smallt *) allocSUndefined();
   3499       break;
   3500     case S_BOOL:
   3501       r = (smallt *) allocSBool(obj->data & 0x10);
   3502       break;
   3503     case S_DICT:
   3504       data     = (char *)&(obj->data);
   3505       //debug - ctx.dbuf = (u8*) data;
   3506       dictNetDeserialLevel2((sDictt **)&r, (u8**)&data, &ctx, /*packed=*/false);
   3507       break;
   3508     case S_DOUBLE:
   3509       data = &(obj->data)+1;
   3510       D = (double *)data;
   3511       r = (smallt *) allocSDouble(*D);
   3512       break;
   3513     case S_INT:
   3514       data  = &(obj->data);
   3515       u64 v = netTypeVarintToUint((u8**)&data);
   3516       v     = (v >> 1) ^ (~(v & 1) + 1);
   3517       r = (smallt *) allocSInt(v);
   3518       break;
   3519     case S_STRING:
   3520       s = (char *)&(obj->data)+1;
   3521       r = (smallt *) allocSStringTiny(s);
   3522       break;
   3523     case S_ARRAY:
   3524       data = (char *)&(obj->data);
   3525       //debug - ctx.dbuf = (u8*) data;
   3526       arrayNetDeserialLevel2((sArrayt **)&r, (u8**)&data, &ctx, /*packed=*/false);
   3527       break;
   3528     case S_BYTES:
   3529       B     = allocSBytes();
   3530       data  = &(obj->data);
   3531       count = netTypeVarintToUint((u8**)&data);
   3532       sBytesPushBuffer(&B, data, count);
   3533       r = (smallt *)B;
   3534       break;
   3535     case UNIFORM_DICT:
   3536       data     = (char *)&(obj->data);
   3537       //debug - ctx.dbuf = (u8*) data;
   3538       uniformDictNetDeserialLevel2((sDictt **)&r, (u8**)&data, &ctx, /*packed=*/false);
   3539       break;
   3540     case UNIFORM_ARRAY:
   3541       data     = (char *)&(obj->data);
   3542       //debug - ctx.dbuf = (u8*) data;
   3543       uniformArrayNetDeserialLevel2((sArrayt **)&r, (u8**)&data, &ctx, /*packed=*/false);
   3544       break;
   3545   }
   3546 
   3547   ret r;
   3548 }
   3549 
   3550 /**
   3551  * deserialize dictionary from data
   3552  *
   3553  * a new dictionary is allocated
   3554  *
   3555  * \param
   3556  *    dict dictionary holding the elements
   3557  *    data serialized dictionary
   3558  */
   3559 internal void dictNetDeserialLevel2(sDictt **dict, u8 **data, contextt *ctx, bool packed) {
   3560   sUndefinedt *u = NULL;
   3561   sBoolt *bo = NULL;
   3562   double *D = NULL;
   3563   sDoublet *Do = NULL;
   3564   sDictt *d = NULL;
   3565   sIntt *io = NULL;
   3566   char *s = NULL;
   3567   sStringt *so = NULL;
   3568   sArrayt *a = NULL;
   3569   sBytest *B = NULL;
   3570   uint32_t count;
   3571   uint32_t dictCount;
   3572 
   3573   if (packed) {
   3574     dictCount = varintToUint(data);
   3575   }
   3576   else {
   3577     if (ctx->nibble == lowNbl) {
   3578       dictCount = netTypeVarintToUint(data);
   3579     }
   3580     else {
   3581       // high nibble
   3582       // type = *(ctx->dbuf + ctx->nblOffset) >> 4;
   3583       #define readTypeInHighNbl\
   3584       ctx->nibble  = lowNbl;\
   3585       if (ctx->nblAddr == *data)\
   3586       /* data points to the type, next byte is count */\
   3587       (*data)++
   3588       readTypeInHighNbl;
   3589       dictCount = varintToUint(data);
   3590     }
   3591   }
   3592 
   3593   if (!dictCount) {
   3594     *dict = allocSDict();
   3595     ret;
   3596   }
   3597 
   3598   loop(dictCount) {
   3599     char *key  = (char*)*data;
   3600     *data     += strlen(key)+1;
   3601     char type;
   3602     if (ctx->nibble == lowNbl) {
   3603       type = (**data) & 0xF;
   3604     }
   3605     else {
   3606       // high nibble
   3607       type = (*ctx->nblAddr) >> 4;
   3608     }
   3609 
   3610     switch(type) {
   3611       case S_UNDEFINED:
   3612         if (ctx->nibble == lowNbl) {
   3613           #define readTypeOnly\
   3614           ctx->nibble  = highNbl;\
   3615           ctx->nblAddr = *data;\
   3616           (*data)++
   3617           readTypeOnly;
   3618         }
   3619         else {
   3620           // high nibble
   3621           readTypeInHighNbl;
   3622         }
   3623         u = allocSUndefined();
   3624         sDictPushTiny(dict, key, (smallt *) u);
   3625         break;
   3626       case S_BOOL:
   3627         if (!ctx->boolAddr) {
   3628           // new packed bools
   3629           if (ctx->nibble == lowNbl) {
   3630             #define read4bPackedBool\
   3631             ctx->boolShift  = 5;\
   3632             ctx->boolAddr   = *data;\
   3633             (*data)++
   3634             read4bPackedBool;
   3635             bo = allocSBool((*ctx->boolAddr) & 0x10);
   3636           }
   3637           else {
   3638             // high nibble
   3639             readTypeInHighNbl;
   3640             #define read8bPackedBool\
   3641             ctx->boolShift  = 1;\
   3642             ctx->boolAddr   = *data;\
   3643             (*data)++
   3644             read8bPackedBool;
   3645             bo = allocSBool((*ctx->boolAddr) & 0x1);
   3646           }
   3647         }
   3648         else {
   3649           // there was a bool before this one, read bits in nibbles
   3650           if (ctx->nibble == lowNbl) {
   3651             if (ctx->boolShift == 8) {
   3652               read4bPackedBool;
   3653               bo = allocSBool((*ctx->boolAddr) & 0x10);
   3654             }
   3655             else {
   3656               readTypeOnly;
   3657               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   3658             }
   3659           }
   3660           else {
   3661             // high nibble
   3662             readTypeInHighNbl;
   3663             if (ctx->boolShift == 8) {
   3664               read8bPackedBool;
   3665               bo = allocSBool((*ctx->boolAddr) & 0x1);
   3666             }
   3667             else {
   3668               // high nibble
   3669               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   3670             }
   3671           }
   3672         }
   3673         sDictPushTiny(dict, key, (smallt *) bo);
   3674         break;
   3675       case S_DICT:
   3676         d = NULL;
   3677         dictNetDeserialLevel2(&d, data, ctx, /*packed=*/false);
   3678         sDictPushTiny(dict, key, (smallt *) d);
   3679         break;
   3680       case S_DOUBLE:
   3681         if (ctx->nibble == lowNbl) {
   3682           readTypeOnly;
   3683         }
   3684         else {
   3685           // high nibble
   3686           readTypeInHighNbl;
   3687         }
   3688         D      = (double *)(*data);
   3689         *data += sizeof(double);
   3690         Do     = allocSDouble(*D);
   3691         sDictPushTiny(dict, key, (smallt *) Do);
   3692         break;
   3693       case S_INT: {
   3694           u64 v;
   3695           if (ctx->nibble == lowNbl) {
   3696             v = netTypeVarintToUint((u8**)data);
   3697           }
   3698           else {
   3699             // high nibble
   3700             readTypeInHighNbl;
   3701             v = varintToUint(data);
   3702           }
   3703           v  = (v >> 1) ^ (~(v & 1) + 1);
   3704           io = allocSInt(v);
   3705           sDictPushTiny(dict, key, (smallt *) io);
   3706         }
   3707         break;
   3708       case S_STRING:
   3709         if (ctx->nibble == lowNbl) {
   3710           readTypeOnly;
   3711         }
   3712         else {
   3713           // high nibble
   3714           readTypeInHighNbl;
   3715         }
   3716         s      = (char *)(*data);
   3717         *data += strlen(s)+1;
   3718         so     = allocSStringTiny(s);
   3719         sDictPushTiny(dict, key, (smallt *) so);
   3720         break;
   3721       case S_ARRAY:
   3722         a = NULL;
   3723         arrayNetDeserialLevel2(&a, data, ctx, /*packed=*/false);
   3724         sDictPushTiny(dict, key, (smallt *) a);
   3725         break;
   3726       case S_BYTES:
   3727         B      = allocSBytes();
   3728         if (ctx->nibble == lowNbl) {
   3729           count  = netTypeVarintToUint((u8**)data);
   3730         }
   3731         else {
   3732           // high nibble
   3733           readTypeInHighNbl;
   3734           count  = varintToUint((u8**)data);
   3735         }
   3736         sBytesPushBuffer(&B, *data, count);
   3737         *data += count;
   3738         sDictPushTiny(dict, key, (smallt *) B);
   3739         break;
   3740       case UNIFORM_DICT:
   3741         d = NULL;
   3742         uniformDictNetDeserialLevel2(&d, data, ctx, /*packed=*/false);
   3743         sDictPushTiny(dict, key, (smallt *) d);
   3744         break;
   3745       case UNIFORM_ARRAY:
   3746         a = NULL;
   3747         uniformArrayNetDeserialLevel2(&a, data, ctx, /*packed=*/false);
   3748         sDictPushTiny(dict, key, (smallt *) a);
   3749         break;
   3750     }
   3751   }
   3752 }
   3753 
   3754 /**
   3755  * deserialize dictionary from data
   3756  *
   3757  * a new dictionary is allocated
   3758  *
   3759  * \param
   3760  *    dict dictionary holding the elements
   3761  *    data serialized dictionary
   3762  */
   3763 internal void uniformDictNetDeserialLevel2(sDictt **dict, u8 **data, contextt *ctx, bool packed) {
   3764   sUndefinedt *u = NULL;
   3765   sBoolt *bo = NULL;
   3766   double *D = NULL;
   3767   sDoublet *Do = NULL;
   3768   sDictt *d = NULL;
   3769   sIntt *io = NULL;
   3770   char *s = NULL;
   3771   sStringt *so = NULL;
   3772   sArrayt *a = NULL;
   3773   sBytest *B = NULL;
   3774   uint32_t count;
   3775   uint32_t dictCount;
   3776   u8 type;
   3777 
   3778   if (packed) {
   3779     type = (**data) & 0xF;
   3780     dictCount = netTypeVarintToUint(data);
   3781   }
   3782   else {
   3783     if (ctx->nibble == lowNbl) {
   3784       type = (**data) >> 4;
   3785       (*data)++;
   3786       dictCount = varintToUint(data);
   3787     }
   3788     else {
   3789       readTypeInHighNbl;
   3790       type = (**data) & 0xF;
   3791       dictCount = netTypeVarintToUint(data);
   3792     }
   3793   }
   3794 
   3795   if (!dictCount) {
   3796     *dict = allocSDict();
   3797     ret;
   3798   }
   3799 
   3800 
   3801   switch(type) {
   3802     case S_UNDEFINED:
   3803       loop(dictCount) {
   3804         char *key  = (char*)*data;
   3805         *data     += strlen(key)+1;
   3806         u = allocSUndefined();
   3807         sDictPushTiny(dict, key, (smallt *) u);
   3808       }
   3809       break;
   3810     case S_BOOL:
   3811       loop(dictCount) {
   3812         char *key  = (char*)*data;
   3813         *data     += strlen(key)+1;
   3814         if (!ctx->boolAddr) {
   3815           read8bPackedBool;
   3816           ctx->boolShift = 0;
   3817         }
   3818         if (ctx->boolShift == 8) {
   3819           readTypeInHighNbl;
   3820           read8bPackedBool;
   3821           bo = allocSBool((*ctx->boolAddr) & 0x1);
   3822         }
   3823         else {
   3824           // high nibble
   3825           readTypeInHighNbl;
   3826           bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   3827         }
   3828         sDictPushTiny(dict, key, (smallt *) bo);
   3829       }
   3830       break;
   3831     case S_DICT:
   3832       loop(dictCount) {
   3833         char *key  = (char*)*data;
   3834         *data     += strlen(key)+1;
   3835         d          = NULL;
   3836         dictNetDeserialLevel2(&d, data, ctx, /*packed=*/true);
   3837         sDictPushTiny(dict, key, (smallt *) d);
   3838       }
   3839       break;
   3840     case S_DOUBLE:
   3841       loop(dictCount) {
   3842         char *key  = (char*)*data;
   3843         *data     += strlen(key)+1;
   3844         D          = (double *)(*data);
   3845         *data     += sizeof(double);
   3846         Do         = allocSDouble(*D);
   3847         sDictPushTiny(dict, key, (smallt *) Do);
   3848       }
   3849       break;
   3850     case S_INT:
   3851       loop(dictCount) {
   3852         char *key  = (char*)*data;
   3853         *data     += strlen(key)+1;
   3854         u64 v      = varintToUint(data);
   3855         v          = (v >> 1) ^ (~(v & 1) + 1);
   3856         io         = allocSInt(v);
   3857         sDictPushTiny(dict, key, (smallt *) io);
   3858       }
   3859       break;
   3860     case S_STRING:
   3861       loop(dictCount) {
   3862         char *key  = (char*)*data;
   3863         *data     += strlen(key)+1;
   3864         s          = (char *)(*data);
   3865         *data     += strlen(s)+1;
   3866         so         = allocSStringTiny(s);
   3867         sDictPushTiny(dict, key, (smallt *) so);
   3868       }
   3869       break;
   3870     case S_ARRAY:
   3871       loop(dictCount) {
   3872         char *key  = (char*)*data;
   3873         *data     += strlen(key)+1;
   3874         a          = NULL;
   3875         arrayNetDeserialLevel2(&a, data, ctx, /*packed=*/true);
   3876         sDictPushTiny(dict, key, (smallt *) a);
   3877       }
   3878       break;
   3879     case S_BYTES:
   3880       loop(dictCount) {
   3881         char *key  = (char*)*data;
   3882         *data     += strlen(key)+1;
   3883         B          = allocSBytes();
   3884         count      = varintToUint((u8**)data);
   3885         sBytesPushBuffer(&B, *data, count);
   3886         *data     += count;
   3887         sDictPushTiny(dict, key, (smallt *) B);
   3888       }
   3889       break;
   3890     case UNIFORM_DICT:
   3891       loop(dictCount) {
   3892         char *key  = (char*)*data;
   3893         *data     += strlen(key)+1;
   3894         d          = NULL;
   3895         uniformDictNetDeserialLevel2(&d, data, ctx, /*packed=*/true);
   3896         sDictPushTiny(dict, key, (smallt *) d);
   3897       }
   3898       break;
   3899     case UNIFORM_ARRAY:
   3900       loop(dictCount) {
   3901         char *key  = (char*)*data;
   3902         *data     += strlen(key)+1;
   3903         a          = NULL;
   3904         uniformArrayNetDeserialLevel2(&a, data, ctx, /*packed=*/true);
   3905         sDictPushTiny(dict, key, (smallt *) a);
   3906       }
   3907       break;
   3908   }
   3909 }
   3910 
   3911 /**
   3912  * deserialize array from data
   3913  *
   3914  * a new array is allocated
   3915  *
   3916  * \param
   3917  *    array holding the elements
   3918  *    data serialized dictionary
   3919  */
   3920 internal void arrayNetDeserialLevel2(sArrayt **array, u8 **data, contextt *ctx, bool packed) {
   3921   sUndefinedt *u = NULL;
   3922   sBoolt *bo = NULL;
   3923   double *D = NULL;
   3924   sDoublet *Do = NULL;
   3925   sDictt *d = NULL;
   3926   sIntt *io = NULL;
   3927   char *s = NULL;
   3928   sStringt *so = NULL;
   3929   sArrayt *a = NULL;
   3930   sBytest *B = NULL;
   3931   uint32_t count;
   3932   uint32_t arrayCount;
   3933 
   3934   if (packed) {
   3935     arrayCount = varintToUint(data);
   3936   }
   3937   else {
   3938     if (ctx->nibble == lowNbl) {
   3939       arrayCount = netTypeVarintToUint(data);
   3940     }
   3941     else {
   3942       // high nibble
   3943       readTypeInHighNbl;
   3944       arrayCount = varintToUint(data);
   3945     }
   3946   }
   3947 
   3948   if (!arrayCount) {
   3949     *array = allocSArray();;
   3950     ret;
   3951   }
   3952 
   3953   loop(arrayCount) {
   3954     char type;
   3955     if (ctx->nibble == lowNbl) {
   3956       type = (**data) & 0xF;
   3957     }
   3958     else {
   3959       // high nibble
   3960       type = (*ctx->nblAddr) >> 4;
   3961     }
   3962 
   3963     switch(type) {
   3964       case S_UNDEFINED:
   3965         if (ctx->nibble == lowNbl) {
   3966           readTypeOnly;
   3967         }
   3968         else {
   3969           // high nibble
   3970           readTypeInHighNbl;
   3971         }
   3972         u = allocSUndefined();
   3973         sArrayPushTiny(array, (smallt *) u);
   3974         break;
   3975       case S_BOOL:
   3976         if (!ctx->boolAddr) {
   3977           // new packed bools
   3978           if (ctx->nibble == lowNbl) {
   3979             read4bPackedBool;
   3980             bo = allocSBool((*ctx->boolAddr) & 0x10);
   3981           }
   3982           else {
   3983             // high nibble
   3984             readTypeInHighNbl;
   3985             read8bPackedBool;
   3986             bo = allocSBool((*ctx->boolAddr) & 0x1);
   3987           }
   3988         }
   3989         else {
   3990           // there was a bool before this one, read bits in nibbles
   3991           if (ctx->nibble == lowNbl) {
   3992             if (ctx->boolShift == 8) {
   3993               read4bPackedBool;
   3994               bo = allocSBool((*ctx->boolAddr) & 0x10);
   3995             }
   3996             else {
   3997               readTypeOnly;
   3998               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   3999             }
   4000           }
   4001           else {
   4002             // high nibble
   4003             readTypeInHighNbl;
   4004             if (ctx->boolShift == 8) {
   4005               read8bPackedBool;
   4006               bo = allocSBool((*ctx->boolAddr) & 0x1);
   4007             }
   4008             else {
   4009               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   4010             }
   4011           }
   4012         }
   4013         sArrayPushTiny(array, (smallt *) bo);
   4014         break;
   4015       case S_DICT:
   4016         d = NULL;
   4017         dictNetDeserialLevel2(&d, data, ctx, /*packed=*/false);
   4018         sArrayPushTiny(array, (smallt *) d);
   4019         break;
   4020       case S_DOUBLE:
   4021         if (ctx->nibble == lowNbl) {
   4022           readTypeOnly;
   4023         }
   4024         else {
   4025           // high nibble
   4026           readTypeInHighNbl;
   4027         }
   4028         D      = (double *)(*data);
   4029         *data += sizeof(double);
   4030         Do     = allocSDouble(*D);
   4031         sArrayPushTiny(array, (smallt *) Do);
   4032         break;
   4033       case S_INT: {
   4034           u64 v;
   4035           if (ctx->nibble == lowNbl) {
   4036             v = netTypeVarintToUint((u8**)data);
   4037           }
   4038           else {
   4039             // high nibble
   4040             readTypeInHighNbl;
   4041             v = varintToUint(data);
   4042           }
   4043           v  = (v >> 1) ^ (~(v & 1) + 1);
   4044           io = allocSInt(v);
   4045           sArrayPushTiny(array, (smallt *) io);
   4046         }
   4047         break;
   4048       case S_STRING:
   4049         if (ctx->nibble == lowNbl) {
   4050           readTypeOnly;
   4051         }
   4052         else {
   4053           // high nibble
   4054           readTypeInHighNbl;
   4055         }
   4056         s      = (char *)(*data);
   4057         *data += strlen(s)+1;
   4058         so     = allocSStringTiny(s);
   4059         sArrayPushTiny(array, (smallt *) so);
   4060         break;
   4061       case S_ARRAY:
   4062         a = NULL;
   4063         arrayNetDeserialLevel2(&a, data, ctx, /*packed=*/false);
   4064         sArrayPushTiny(array, (smallt *) a);
   4065         break;
   4066       case S_BYTES:
   4067         B      = allocSBytes();
   4068         if (ctx->nibble == lowNbl) {
   4069           count  = netTypeVarintToUint((u8**)data);
   4070         }
   4071         else {
   4072           // high nibble
   4073           readTypeInHighNbl;
   4074           count  = varintToUint((u8**)data);
   4075         }
   4076         sBytesPushBuffer(&B, *data, count);
   4077         *data += count;
   4078         sArrayPushTiny(array, (smallt *) B);
   4079         break;
   4080       case UNIFORM_DICT:
   4081         d = NULL;
   4082         uniformDictNetDeserialLevel2(&d, data, ctx, /*packed=*/false);
   4083         sArrayPushTiny(array, (smallt *) d);
   4084         break;
   4085       case UNIFORM_ARRAY:
   4086         a = NULL;
   4087         uniformArrayNetDeserialLevel2(&a, data, ctx, /*packed=*/false);
   4088         sArrayPushTiny(array, (smallt *) a);
   4089         break;
   4090     }
   4091   }
   4092 }
   4093 
   4094 internal void uniformArrayNetDeserialLevel2(sArrayt **array, u8 **data, contextt *ctx, bool packed) {
   4095   sUndefinedt *u = NULL;
   4096   sBoolt *bo = NULL;
   4097   double *D = NULL;
   4098   sDoublet *Do = NULL;
   4099   sDictt *d = NULL;
   4100   sIntt *io = NULL;
   4101   char *s = NULL;
   4102   sStringt *so = NULL;
   4103   sArrayt *a = NULL;
   4104   sBytest *B = NULL;
   4105   uint32_t count;
   4106   uint32_t arrayCount;
   4107   u8 type;
   4108 
   4109   if (packed) {
   4110     type = (**data) & 0xF;
   4111     arrayCount = netTypeVarintToUint(data);
   4112   }
   4113   else {
   4114     if (ctx->nibble == lowNbl) {
   4115       type = (**data) >> 4;
   4116       (*data)++;
   4117       arrayCount = varintToUint(data);
   4118     }
   4119     else {
   4120       readTypeInHighNbl;
   4121       type = (**data) & 0xF;
   4122       arrayCount = netTypeVarintToUint(data);
   4123     }
   4124   }
   4125 
   4126   if (!arrayCount) {
   4127     *array = allocSArray();;
   4128     ret;
   4129   }
   4130 
   4131   switch(type) {
   4132     case S_UNDEFINED:
   4133       loop(arrayCount) {
   4134         u = allocSUndefined();
   4135         sArrayPushTiny(array, (smallt *) u);
   4136       }
   4137       break;
   4138     case S_BOOL:
   4139       loop(arrayCount) {
   4140         if (!ctx->boolAddr) {
   4141           read8bPackedBool;
   4142           ctx->boolShift = 0;
   4143         }
   4144         if (ctx->boolShift == 8) {
   4145           read8bPackedBool;
   4146           bo = allocSBool((*ctx->boolAddr) & 0x1);
   4147         }
   4148         else {
   4149           bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   4150         }
   4151         sArrayPushTiny(array, (smallt *) bo);
   4152       }
   4153       break;
   4154     case S_DICT:
   4155       loop(arrayCount) {
   4156         d = NULL;
   4157         dictNetDeserialLevel2(&d, data, ctx, /*packed=*/true);
   4158         sArrayPushTiny(array, (smallt *) d);
   4159       }
   4160       break;
   4161     case S_DOUBLE:
   4162       loop(arrayCount) {
   4163         D      = (double *)(*data);
   4164         *data += sizeof(double);
   4165         Do     = allocSDouble(*D);
   4166         sArrayPushTiny(array, (smallt *) Do);
   4167       }
   4168       break;
   4169     case S_INT:
   4170       loop(arrayCount) {
   4171         u64 v = varintToUint(data);
   4172         v     = (v >> 1) ^ (~(v & 1) + 1);
   4173         io    = allocSInt(v);
   4174         sArrayPushTiny(array, (smallt *) io);
   4175       }
   4176       break;
   4177     case S_STRING:
   4178       loop(arrayCount) {
   4179         s      = (char *)(*data);
   4180         *data += strlen(s)+1;
   4181         so     = allocSStringTiny(s);
   4182         sArrayPushTiny(array, (smallt *) so);
   4183       }
   4184       break;
   4185     case S_ARRAY:
   4186       loop(arrayCount) {
   4187         a = NULL;
   4188         arrayNetDeserialLevel2(&a, data, ctx, /*packed=*/true);
   4189         sArrayPushTiny(array, (smallt *) a);
   4190       }
   4191       break;
   4192     case S_BYTES:
   4193       loop(arrayCount) {
   4194         B      = allocSBytes();
   4195         count  = varintToUint((u8**)data);
   4196         sBytesPushBuffer(&B, *data, count);
   4197         *data += count;
   4198         sArrayPushTiny(array, (smallt *) B);
   4199       }
   4200       break;
   4201     case UNIFORM_DICT:
   4202       loop(arrayCount) {
   4203         d = NULL;
   4204         uniformDictNetDeserialLevel2(&d, data, ctx, /*packed=*/true);
   4205         sArrayPushTiny(array, (smallt *) d);
   4206       }
   4207       break;
   4208     case UNIFORM_ARRAY:
   4209       loop(arrayCount) {
   4210         a = NULL;
   4211         uniformArrayNetDeserialLevel2(&a, data, ctx, /*packed=*/true);
   4212         sArrayPushTiny(array, (smallt *) a);
   4213       }
   4214       break;
   4215   }
   4216 }
   4217 
   4218 internal smallJsont* deserialNetSerialLevel2(smallJsont *self, smallBytest *data) {
   4219 
   4220   if (!data or !data->B or !data->B->count) {
   4221     ret self;
   4222   }
   4223 
   4224   smallt *o = netDeserialLevel2(data->B);
   4225 
   4226   if (!o) {
   4227     ret self;
   4228   }
   4229 
   4230   freeG(self);
   4231 
   4232   setsoG(self, o);
   4233 
   4234   ret self;
   4235 }
   4236 
   4237 // level 3
   4238 // like level 2, elements of identical type in a row are packed
   4239 
   4240 /**
   4241  * deserializer top function
   4242  */
   4243 internal smallt* netDeserial(sBytest *obj) {
   4244   smallt   *r = NULL;
   4245   double   *D = NULL;
   4246   char     *s = NULL;
   4247   sBytest  *B = NULL;
   4248   uint32_t count;
   4249   char     *data  = NULL;
   4250   contextt ctx = {.nibble=lowNbl, .nblAddr=NULL, .boolShift = 0, .boolAddr=NULL};
   4251 
   4252   switch(obj->data & 0xF) {
   4253     case S_UNDEFINED:
   4254       r = (smallt *) allocSUndefined();
   4255       break;
   4256     case S_BOOL:
   4257       r = (smallt *) allocSBool(obj->data & 0x10);
   4258       break;
   4259     case S_DICT:
   4260       data     = (char *)&(obj->data);
   4261       //debug - ctx.dbuf = (u8*) data;
   4262       dictNetDeserial((sDictt **)&r, (u8**)&data, &ctx, /*packed=*/false);
   4263       break;
   4264     case S_DOUBLE:
   4265       data = &(obj->data)+1;
   4266       D = (double *)data;
   4267       r = (smallt *) allocSDouble(*D);
   4268       break;
   4269     case S_INT:
   4270       data  = &(obj->data);
   4271       u64 v = netTypeVarintToUint((u8**)&data);
   4272       v = (v >> 1) ^ (~(v & 1) + 1);
   4273       r = (smallt *) allocSInt(v);
   4274       break;
   4275     case S_STRING:
   4276       s = (char *)&(obj->data)+1;
   4277       r = (smallt *) allocSStringTiny(s);
   4278       break;
   4279     case S_ARRAY:
   4280       data = (char *)&(obj->data);
   4281       //debug - ctx.dbuf = (u8*) data;
   4282       arrayNetDeserial((sArrayt **)&r, (u8**)&data, &ctx, /*packed=*/false);
   4283       break;
   4284     case S_BYTES:
   4285       B     = allocSBytes();
   4286       data  = &(obj->data);
   4287       count = netTypeVarintToUint((u8**)&data);
   4288       sBytesPushBuffer(&B, data, count);
   4289       r = (smallt *)B;
   4290       break;
   4291     case UNIFORM_DICT:
   4292       data     = (char *)&(obj->data);
   4293       //debug - ctx.dbuf = (u8*) data;
   4294       uniformDictNetDeserial((sDictt **)&r, (u8**)&data, &ctx, /*packed=*/false);
   4295       break;
   4296     case UNIFORM_ARRAY:
   4297       data     = (char *)&(obj->data);
   4298       //debug - ctx.dbuf = (u8*) data;
   4299       uniformArrayNetDeserial((sArrayt **)&r, (u8**)&data, &ctx, /*packed=*/false);
   4300       break;
   4301   }
   4302 
   4303   ret r;
   4304 }
   4305 
   4306 /**
   4307  * deserialize dictionary from data
   4308  *
   4309  * a new dictionary is allocated
   4310  *
   4311  * \param
   4312  *    dict dictionary holding the elements
   4313  *    data serialized dictionary
   4314  */
   4315 internal void dictNetDeserial(sDictt **dict, u8 **data, contextt *ctx, bool packed) {
   4316   sUndefinedt *u = NULL;
   4317   sBoolt *bo = NULL;
   4318   double *D = NULL;
   4319   sDoublet *Do = NULL;
   4320   sDictt *d = NULL;
   4321   sIntt *io = NULL;
   4322   char *s = NULL;
   4323   sStringt *so = NULL;
   4324   sArrayt *a = NULL;
   4325   sBytest *B = NULL;
   4326   uint32_t count;
   4327   uint32_t dictCount;
   4328 
   4329   if (packed) {
   4330     dictCount = varintToUint(data);
   4331   }
   4332   else {
   4333     if (ctx->nibble == lowNbl) {
   4334       dictCount = netTypeVarintToUint(data);
   4335     }
   4336     else {
   4337       // high nibble
   4338       // type = *(ctx->dbuf + ctx->nblOffset) >> 4;
   4339       #define readTypeInHighNbl\
   4340       ctx->nibble  = lowNbl;\
   4341       if (ctx->nblAddr == *data)\
   4342       /* data points to the type, next byte is count */\
   4343       (*data)++
   4344       readTypeInHighNbl;
   4345       dictCount = varintToUint(data);
   4346     }
   4347   }
   4348 
   4349   if (!dictCount) {
   4350     *dict = allocSDict();
   4351     ret;
   4352   }
   4353 
   4354   bool inPack = false;
   4355   u8 packedType;
   4356   size_t packCount;
   4357   loop(dictCount) {
   4358     char *key  = (char*)*data;
   4359     *data     += strlen(key)+1;
   4360     char type;
   4361     if (inPack) {
   4362       type = packedType;
   4363     }
   4364     else {
   4365       if (ctx->nibble == lowNbl) {
   4366         type = (**data) & 0xF;
   4367       }
   4368       else {
   4369         // high nibble
   4370         type = (*ctx->nblAddr) >> 4;
   4371       }
   4372     }
   4373 
   4374     switch(type) {
   4375       case S_UNDEFINED:
   4376         if (ctx->nibble == lowNbl) {
   4377           #define readTypeOnly\
   4378           ctx->nibble  = highNbl;\
   4379           ctx->nblAddr = *data;\
   4380           (*data)++
   4381           readTypeOnly;
   4382         }
   4383         else {
   4384           // high nibble
   4385           readTypeInHighNbl;
   4386         }
   4387         u = allocSUndefined();
   4388         sDictPushTiny(dict, key, (smallt *) u);
   4389         break;
   4390       case S_BOOL:
   4391         if (!ctx->boolAddr) {
   4392           // new packed bools
   4393           if (ctx->nibble == lowNbl) {
   4394             #define read4bPackedBool\
   4395             ctx->boolShift  = 5;\
   4396             ctx->boolAddr   = *data;\
   4397             (*data)++
   4398             read4bPackedBool;
   4399             bo = allocSBool((*ctx->boolAddr) & 0x10);
   4400           }
   4401           else {
   4402             // high nibble
   4403             readTypeInHighNbl;
   4404             #define read8bPackedBool\
   4405             ctx->boolShift  = 1;\
   4406             ctx->boolAddr   = *data;\
   4407             (*data)++
   4408             read8bPackedBool;
   4409             bo = allocSBool((*ctx->boolAddr) & 0x1);
   4410           }
   4411         }
   4412         else {
   4413           // there was a bool before this one, read bits in nibbles
   4414           if (ctx->nibble == lowNbl) {
   4415             if (ctx->boolShift == 8) {
   4416               read4bPackedBool;
   4417               bo = allocSBool((*ctx->boolAddr) & 0x10);
   4418             }
   4419             else {
   4420               readTypeOnly;
   4421               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   4422             }
   4423           }
   4424           else {
   4425             // high nibble
   4426             readTypeInHighNbl;
   4427             if (ctx->boolShift == 8) {
   4428               read8bPackedBool;
   4429               bo = allocSBool((*ctx->boolAddr) & 0x1);
   4430             }
   4431             else {
   4432               // high nibble
   4433               readTypeInHighNbl;
   4434               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   4435             }
   4436           }
   4437         }
   4438         sDictPushTiny(dict, key, (smallt *) bo);
   4439         break;
   4440       case S_DICT:
   4441         d = NULL;
   4442         dictNetDeserial(&d, data, ctx, /*packed=*/false);
   4443         sDictPushTiny(dict, key, (smallt *) d);
   4444         break;
   4445       case S_DOUBLE:
   4446         if (ctx->nibble == lowNbl) {
   4447           readTypeOnly;
   4448         }
   4449         else {
   4450           // high nibble
   4451           readTypeInHighNbl;
   4452         }
   4453         D      = (double *)(*data);
   4454         *data += sizeof(double);
   4455         Do     = allocSDouble(*D);
   4456         sDictPushTiny(dict, key, (smallt *) Do);
   4457         break;
   4458       case S_INT: {
   4459           u64 v;
   4460           if (ctx->nibble == lowNbl) {
   4461             v = netTypeVarintToUint((u8**)data);
   4462           }
   4463           else {
   4464             // high nibble
   4465             readTypeInHighNbl;
   4466             v = varintToUint(data);
   4467           }
   4468           v  = (v >> 1) ^ (~(v & 1) + 1);
   4469           io = allocSInt(v);
   4470           sDictPushTiny(dict, key, (smallt *) io);
   4471         }
   4472         break;
   4473       case S_STRING:
   4474         if (ctx->nibble == lowNbl) {
   4475           readTypeOnly;
   4476         }
   4477         else {
   4478           // high nibble
   4479           readTypeInHighNbl;
   4480         }
   4481         s      = (char *)(*data);
   4482         *data += strlen(s)+1;
   4483         so     = allocSStringTiny(s);
   4484         sDictPushTiny(dict, key, (smallt *) so);
   4485         break;
   4486       case S_ARRAY:
   4487         a = NULL;
   4488         arrayNetDeserial(&a, data, ctx, /*packed=*/false);
   4489         sDictPushTiny(dict, key, (smallt *) a);
   4490         break;
   4491       case S_BYTES:
   4492         B      = allocSBytes();
   4493         if (ctx->nibble == lowNbl) {
   4494           count  = netTypeVarintToUint((u8**)data);
   4495         }
   4496         else {
   4497           // high nibble
   4498           readTypeInHighNbl;
   4499           count  = varintToUint((u8**)data);
   4500         }
   4501         sBytesPushBuffer(&B, *data, count);
   4502         *data += count;
   4503         sDictPushTiny(dict, key, (smallt *) B);
   4504         break;
   4505       case PK_DICT:
   4506         if (!inPack) {
   4507           inPack = true;
   4508           if (ctx->nibble == lowNbl) {
   4509             packCount  = netTypeVarintToUint((u8**)data);
   4510           }
   4511           else {
   4512             // high nibble
   4513             readTypeInHighNbl;
   4514             packCount  = varintToUint((u8**)data);
   4515           }
   4516           packedType = PK_DICT;
   4517         }
   4518 
   4519         d = NULL;
   4520         dictNetDeserial(&d, data, ctx, /*packed=*/true);
   4521         sDictPushTiny(dict, key, (smallt *) d);
   4522         // stop unpacking when packCount == 0
   4523         packCount--;
   4524         if (!packCount) inPack = false;
   4525         break;
   4526       case PK_DOUBLE:
   4527         if (!inPack) {
   4528           inPack = true;
   4529           if (ctx->nibble == lowNbl) {
   4530             packCount  = netTypeVarintToUint((u8**)data);
   4531           }
   4532           else {
   4533             // high nibble
   4534             readTypeInHighNbl;
   4535             packCount  = varintToUint((u8**)data);
   4536           }
   4537           packedType = PK_DOUBLE;
   4538         }
   4539 
   4540         D      = (double *)(*data);
   4541         *data += sizeof(double);
   4542         Do     = allocSDouble(*D);
   4543         sDictPushTiny(dict, key, (smallt *) Do);
   4544         // stop unpacking when packCount == 0
   4545         packCount--;
   4546         if (!packCount) inPack = false;
   4547         break;
   4548       case PK_INT:
   4549         if (!inPack) {
   4550           inPack = true;
   4551           if (ctx->nibble == lowNbl) {
   4552             packCount  = netTypeVarintToUint((u8**)data);
   4553           }
   4554           else {
   4555             // high nibble
   4556             readTypeInHighNbl;
   4557             packCount  = varintToUint((u8**)data);
   4558           }
   4559           packedType = PK_INT;
   4560         }
   4561 
   4562         u64 v = varintToUint(data);
   4563         v     = (v >> 1) ^ (~(v & 1) + 1);
   4564         io    = allocSInt(v);
   4565         sDictPushTiny(dict, key, (smallt *) io);
   4566         // stop unpacking when packCount == 0
   4567         packCount--;
   4568         if (!packCount) inPack = false;
   4569         break;
   4570       case PK_STRING:
   4571         if (!inPack) {
   4572           inPack = true;
   4573           if (ctx->nibble == lowNbl) {
   4574             packCount  = netTypeVarintToUint((u8**)data);
   4575           }
   4576           else {
   4577             // high nibble
   4578             readTypeInHighNbl;
   4579             packCount  = varintToUint((u8**)data);
   4580           }
   4581           packedType = PK_STRING;
   4582         }
   4583 
   4584         s          = (char *)(*data);
   4585         *data     += strlen(s)+1;
   4586         so         = allocSStringTiny(s);
   4587         sDictPushTiny(dict, key, (smallt *) so);
   4588         // stop unpacking when packCount == 0
   4589         packCount--;
   4590         if (!packCount) inPack = false;
   4591         break;
   4592       case PK_ARRAY:
   4593         if (!inPack) {
   4594           inPack = true;
   4595           if (ctx->nibble == lowNbl) {
   4596             packCount  = netTypeVarintToUint((u8**)data);
   4597           }
   4598           else {
   4599             // high nibble
   4600             readTypeInHighNbl;
   4601             packCount  = varintToUint((u8**)data);
   4602           }
   4603           packedType = PK_ARRAY;
   4604         }
   4605 
   4606         a          = NULL;
   4607         arrayNetDeserial(&a, data, ctx, /*packed=*/true);
   4608         sDictPushTiny(dict, key, (smallt *) a);
   4609         // stop unpacking when packCount == 0
   4610         packCount--;
   4611         if (!packCount) inPack = false;
   4612         break;
   4613       case PK_BYTES:
   4614         if (!inPack) {
   4615           inPack = true;
   4616           if (ctx->nibble == lowNbl) {
   4617             packCount  = netTypeVarintToUint((u8**)data);
   4618           }
   4619           else {
   4620             // high nibble
   4621             readTypeInHighNbl;
   4622             packCount  = varintToUint((u8**)data);
   4623           }
   4624           packedType = PK_BYTES;
   4625         }
   4626 
   4627         B          = allocSBytes();
   4628         count      = varintToUint((u8**)data);
   4629         sBytesPushBuffer(&B, *data, count);
   4630         *data     += count;
   4631         sDictPushTiny(dict, key, (smallt *) B);
   4632         // stop unpacking when packCount == 0
   4633         packCount--;
   4634         if (!packCount) inPack = false;
   4635         break;
   4636       case UNIFORM_DICT:
   4637         d = NULL;
   4638         uniformDictNetDeserial(&d, data, ctx, /*packed=*/false);
   4639         sDictPushTiny(dict, key, (smallt *) d);
   4640         break;
   4641       case UNIFORM_ARRAY:
   4642         a = NULL;
   4643         uniformArrayNetDeserial(&a, data, ctx, /*packed=*/false);
   4644         sDictPushTiny(dict, key, (smallt *) a);
   4645         break;
   4646     }
   4647   }
   4648 }
   4649 
   4650 /**
   4651  * deserialize dictionary from data
   4652  *
   4653  * a new dictionary is allocated
   4654  *
   4655  * \param
   4656  *    dict dictionary holding the elements
   4657  *    data serialized dictionary
   4658  */
   4659 internal void uniformDictNetDeserial(sDictt **dict, u8 **data, contextt *ctx, bool packed) {
   4660   sUndefinedt *u = NULL;
   4661   sBoolt *bo = NULL;
   4662   double *D = NULL;
   4663   sDoublet *Do = NULL;
   4664   sDictt *d = NULL;
   4665   sIntt *io = NULL;
   4666   char *s = NULL;
   4667   sStringt *so = NULL;
   4668   sArrayt *a = NULL;
   4669   sBytest *B = NULL;
   4670   uint32_t count;
   4671   uint32_t dictCount;
   4672   u8 type;
   4673 
   4674   if (packed) {
   4675     type = (**data) & 0xF;
   4676     dictCount = netTypeVarintToUint(data);
   4677   }
   4678   else {
   4679     if (ctx->nibble == lowNbl) {
   4680       type = (**data) >> 4;
   4681       (*data)++;
   4682       dictCount = varintToUint(data);
   4683     }
   4684     else {
   4685       readTypeInHighNbl;
   4686       type = (**data) & 0xF;
   4687       dictCount = netTypeVarintToUint(data);
   4688     }
   4689   }
   4690 
   4691   if (!dictCount) {
   4692     *dict = allocSDict();
   4693     ret;
   4694   }
   4695 
   4696 
   4697   switch(type) {
   4698     case S_UNDEFINED:
   4699       loop(dictCount) {
   4700         char *key  = (char*)*data;
   4701         *data     += strlen(key)+1;
   4702         u = allocSUndefined();
   4703         sDictPushTiny(dict, key, (smallt *) u);
   4704       }
   4705       break;
   4706     case S_BOOL:
   4707       loop(dictCount) {
   4708         char *key  = (char*)*data;
   4709         *data     += strlen(key)+1;
   4710         if (!ctx->boolAddr) {
   4711           read8bPackedBool;
   4712           ctx->boolShift = 0;
   4713         }
   4714         if (ctx->boolShift == 8) {
   4715           readTypeInHighNbl;
   4716           read8bPackedBool;
   4717           bo = allocSBool((*ctx->boolAddr) & 0x1);
   4718         }
   4719         else {
   4720           // high nibble
   4721           readTypeInHighNbl;
   4722           bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   4723         }
   4724         sDictPushTiny(dict, key, (smallt *) bo);
   4725       }
   4726       break;
   4727     case S_DICT:
   4728       loop(dictCount) {
   4729         char *key  = (char*)*data;
   4730         *data     += strlen(key)+1;
   4731         d          = NULL;
   4732         dictNetDeserial(&d, data, ctx, /*packed=*/true);
   4733         sDictPushTiny(dict, key, (smallt *) d);
   4734       }
   4735       break;
   4736     case S_DOUBLE:
   4737       loop(dictCount) {
   4738         char *key  = (char*)*data;
   4739         *data     += strlen(key)+1;
   4740         D          = (double *)(*data);
   4741         *data     += sizeof(double);
   4742         Do         = allocSDouble(*D);
   4743         sDictPushTiny(dict, key, (smallt *) Do);
   4744       }
   4745       break;
   4746     case S_INT:
   4747       loop(dictCount) {
   4748         char *key  = (char*)*data;
   4749         *data     += strlen(key)+1;
   4750         u64 v      = varintToUint(data);
   4751         v          = (v >> 1) ^ (~(v & 1) + 1);
   4752         io         = allocSInt(v);
   4753         sDictPushTiny(dict, key, (smallt *) io);
   4754       }
   4755       break;
   4756     case S_STRING:
   4757       loop(dictCount) {
   4758         char *key  = (char*)*data;
   4759         *data     += strlen(key)+1;
   4760         s          = (char *)(*data);
   4761         *data     += strlen(s)+1;
   4762         so         = allocSStringTiny(s);
   4763         sDictPushTiny(dict, key, (smallt *) so);
   4764       }
   4765       break;
   4766     case S_ARRAY:
   4767       loop(dictCount) {
   4768         char *key  = (char*)*data;
   4769         *data     += strlen(key)+1;
   4770         a          = NULL;
   4771         arrayNetDeserial(&a, data, ctx, /*packed=*/true);
   4772         sDictPushTiny(dict, key, (smallt *) a);
   4773       }
   4774       break;
   4775     case S_BYTES:
   4776       loop(dictCount) {
   4777         char *key  = (char*)*data;
   4778         *data     += strlen(key)+1;
   4779         B          = allocSBytes();
   4780         count      = varintToUint((u8**)data);
   4781         sBytesPushBuffer(&B, *data, count);
   4782         *data     += count;
   4783         sDictPushTiny(dict, key, (smallt *) B);
   4784       }
   4785       break;
   4786     case UNIFORM_DICT:
   4787       loop(dictCount) {
   4788         char *key  = (char*)*data;
   4789         *data     += strlen(key)+1;
   4790         d          = NULL;
   4791         uniformDictNetDeserial(&d, data, ctx, /*packed=*/true);
   4792         sDictPushTiny(dict, key, (smallt *) d);
   4793       }
   4794       break;
   4795     case UNIFORM_ARRAY:
   4796       loop(dictCount) {
   4797         char *key  = (char*)*data;
   4798         *data     += strlen(key)+1;
   4799         a          = NULL;
   4800         uniformArrayNetDeserial(&a, data, ctx, /*packed=*/true);
   4801         sDictPushTiny(dict, key, (smallt *) a);
   4802       }
   4803       break;
   4804   }
   4805 }
   4806 
   4807 /**
   4808  * deserialize array from data
   4809  *
   4810  * a new array is allocated
   4811  *
   4812  * \param
   4813  *    array holding the elements
   4814  *    data serialized dictionary
   4815  */
   4816 internal void arrayNetDeserial(sArrayt **array, u8 **data, contextt *ctx, bool packed) {
   4817   sUndefinedt *u = NULL;
   4818   sBoolt *bo = NULL;
   4819   double *D = NULL;
   4820   sDoublet *Do = NULL;
   4821   sDictt *d = NULL;
   4822   sIntt *io = NULL;
   4823   char *s = NULL;
   4824   sStringt *so = NULL;
   4825   sArrayt *a = NULL;
   4826   sBytest *B = NULL;
   4827   uint32_t count;
   4828   uint32_t arrayCount;
   4829 
   4830   if (packed) {
   4831     arrayCount = varintToUint(data);
   4832   }
   4833   else {
   4834     if (ctx->nibble == lowNbl) {
   4835       arrayCount = netTypeVarintToUint(data);
   4836     }
   4837     else {
   4838       // high nibble
   4839       readTypeInHighNbl;
   4840       arrayCount = varintToUint(data);
   4841     }
   4842   }
   4843 
   4844   if (!arrayCount) {
   4845     *array = allocSArray();;
   4846     ret;
   4847   }
   4848 
   4849   bool inPack = false;
   4850   u8 packedType;
   4851   size_t packCount;
   4852   loop(arrayCount) {
   4853     char type;
   4854     if (inPack) {
   4855       type = packedType;
   4856     }
   4857     else {
   4858       if (ctx->nibble == lowNbl) {
   4859         type = (**data) & 0xF;
   4860       }
   4861       else {
   4862         // high nibble
   4863         type = (*ctx->nblAddr) >> 4;
   4864       }
   4865     }
   4866 
   4867     switch(type) {
   4868       case S_UNDEFINED:
   4869         if (ctx->nibble == lowNbl) {
   4870           readTypeOnly;
   4871         }
   4872         else {
   4873           // high nibble
   4874           readTypeInHighNbl;
   4875         }
   4876         u = allocSUndefined();
   4877         sArrayPushTiny(array, (smallt *) u);
   4878         break;
   4879       case S_BOOL:
   4880         if (!ctx->boolAddr) {
   4881           // new packed bools
   4882           if (ctx->nibble == lowNbl) {
   4883             read4bPackedBool;
   4884             bo = allocSBool((*ctx->boolAddr) & 0x10);
   4885           }
   4886           else {
   4887             // high nibble
   4888             readTypeInHighNbl;
   4889             read8bPackedBool;
   4890             bo = allocSBool((*ctx->boolAddr) & 0x1);
   4891           }
   4892         }
   4893         else {
   4894           // there was a bool before this one, read bits in nibbles
   4895           if (ctx->nibble == lowNbl) {
   4896             if (ctx->boolShift == 8) {
   4897               read4bPackedBool;
   4898               bo = allocSBool((*ctx->boolAddr) & 0x10);
   4899             }
   4900             else {
   4901               readTypeOnly;
   4902               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   4903             }
   4904           }
   4905           else {
   4906             // high nibble
   4907             readTypeInHighNbl;
   4908             if (ctx->boolShift == 8) {
   4909               read8bPackedBool;
   4910               bo = allocSBool((*ctx->boolAddr) & 0x1);
   4911             }
   4912             else {
   4913               bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   4914             }
   4915           }
   4916         }
   4917         sArrayPushTiny(array, (smallt *) bo);
   4918         break;
   4919       case S_DICT:
   4920         d = NULL;
   4921         dictNetDeserial(&d, data, ctx, /*packed=*/false);
   4922         sArrayPushTiny(array, (smallt *) d);
   4923         break;
   4924       case S_DOUBLE:
   4925         if (ctx->nibble == lowNbl) {
   4926           readTypeOnly;
   4927         }
   4928         else {
   4929           // high nibble
   4930           readTypeInHighNbl;
   4931         }
   4932         D      = (double *)(*data);
   4933         *data += sizeof(double);
   4934         Do     = allocSDouble(*D);
   4935         sArrayPushTiny(array, (smallt *) Do);
   4936         break;
   4937       case S_INT: {
   4938           u64 v;
   4939           if (ctx->nibble == lowNbl) {
   4940             v = netTypeVarintToUint((u8**)data);
   4941           }
   4942           else {
   4943             // high nibble
   4944             readTypeInHighNbl;
   4945             v = varintToUint(data);
   4946           }
   4947           v  = (v >> 1) ^ (~(v & 1) + 1);
   4948           io = allocSInt(v);
   4949           sArrayPushTiny(array, (smallt *) io);
   4950         }
   4951         break;
   4952       case S_STRING:
   4953         if (ctx->nibble == lowNbl) {
   4954           readTypeOnly;
   4955         }
   4956         else {
   4957           // high nibble
   4958           readTypeInHighNbl;
   4959         }
   4960         s      = (char *)(*data);
   4961         *data += strlen(s)+1;
   4962         so     = allocSStringTiny(s);
   4963         sArrayPushTiny(array, (smallt *) so);
   4964         break;
   4965       case S_ARRAY:
   4966         a = NULL;
   4967         arrayNetDeserial(&a, data, ctx, /*packed=*/false);
   4968         sArrayPushTiny(array, (smallt *) a);
   4969         break;
   4970       case S_BYTES:
   4971         B      = allocSBytes();
   4972         if (ctx->nibble == lowNbl) {
   4973           count  = netTypeVarintToUint((u8**)data);
   4974         }
   4975         else {
   4976           // high nibble
   4977           readTypeInHighNbl;
   4978           count  = varintToUint((u8**)data);
   4979         }
   4980         sBytesPushBuffer(&B, *data, count);
   4981         *data += count;
   4982         sArrayPushTiny(array, (smallt *) B);
   4983         break;
   4984       case PK_DICT:
   4985         if (!inPack) {
   4986           inPack = true;
   4987           if (ctx->nibble == lowNbl) {
   4988             packCount  = netTypeVarintToUint((u8**)data);
   4989           }
   4990           else {
   4991             // high nibble
   4992             readTypeInHighNbl;
   4993             packCount  = varintToUint((u8**)data);
   4994           }
   4995           packedType = PK_DICT;
   4996         }
   4997 
   4998         d = NULL;
   4999         dictNetDeserial(&d, data, ctx, /*packed=*/true);
   5000         sArrayPushTiny(array, (smallt *) d);
   5001         // stop unpacking when packCount == 0
   5002         packCount--;
   5003         if (!packCount) inPack = false;
   5004         break;
   5005       case PK_DOUBLE:
   5006         if (!inPack) {
   5007           inPack = true;
   5008           if (ctx->nibble == lowNbl) {
   5009             packCount  = netTypeVarintToUint((u8**)data);
   5010           }
   5011           else {
   5012             // high nibble
   5013             readTypeInHighNbl;
   5014             packCount  = varintToUint((u8**)data);
   5015           }
   5016           packedType = PK_DOUBLE;
   5017         }
   5018 
   5019         D      = (double *)(*data);
   5020         *data += sizeof(double);
   5021         Do     = allocSDouble(*D);
   5022         sArrayPushTiny(array, (smallt *) Do);
   5023         // stop unpacking when packCount == 0
   5024         packCount--;
   5025         if (!packCount) inPack = false;
   5026         break;
   5027       case PK_INT:
   5028         if (!inPack) {
   5029           inPack = true;
   5030           if (ctx->nibble == lowNbl) {
   5031             packCount  = netTypeVarintToUint((u8**)data);
   5032           }
   5033           else {
   5034             // high nibble
   5035             readTypeInHighNbl;
   5036             packCount  = varintToUint((u8**)data);
   5037           }
   5038           packedType = PK_INT;
   5039         }
   5040 
   5041         u64 v = varintToUint(data);
   5042         v     = (v >> 1) ^ (~(v & 1) + 1);
   5043         io     = allocSInt(v);
   5044         sArrayPushTiny(array, (smallt *) io);
   5045         // stop unpacking when packCount == 0
   5046         packCount--;
   5047         if (!packCount) inPack = false;
   5048         break;
   5049       case PK_STRING:
   5050         if (!inPack) {
   5051           inPack = true;
   5052           if (ctx->nibble == lowNbl) {
   5053             packCount  = netTypeVarintToUint((u8**)data);
   5054           }
   5055           else {
   5056             // high nibble
   5057             readTypeInHighNbl;
   5058             packCount  = varintToUint((u8**)data);
   5059           }
   5060           packedType = PK_STRING;
   5061         }
   5062 
   5063         s      = (char *)(*data);
   5064         *data += strlen(s)+1;
   5065         so     = allocSStringTiny(s);
   5066         sArrayPushTiny(array, (smallt *) so);
   5067         // stop unpacking when packCount == 0
   5068         packCount--;
   5069         if (!packCount) inPack = false;
   5070         break;
   5071       case PK_ARRAY:
   5072         if (!inPack) {
   5073           inPack = true;
   5074           if (ctx->nibble == lowNbl) {
   5075             packCount  = netTypeVarintToUint((u8**)data);
   5076           }
   5077           else {
   5078             // high nibble
   5079             readTypeInHighNbl;
   5080             packCount  = varintToUint((u8**)data);
   5081           }
   5082           packedType = PK_ARRAY;
   5083         }
   5084 
   5085         a = NULL;
   5086         arrayNetDeserial(&a, data, ctx, /*packed=*/true);
   5087         sArrayPushTiny(array, (smallt *) a);
   5088         // stop unpacking when packCount == 0
   5089         packCount--;
   5090         if (!packCount) inPack = false;
   5091         break;
   5092       case PK_BYTES:
   5093         if (!inPack) {
   5094           inPack = true;
   5095           if (ctx->nibble == lowNbl) {
   5096             packCount  = netTypeVarintToUint((u8**)data);
   5097           }
   5098           else {
   5099             // high nibble
   5100             readTypeInHighNbl;
   5101             packCount  = varintToUint((u8**)data);
   5102           }
   5103           packedType = PK_BYTES;
   5104         }
   5105 
   5106         B      = allocSBytes();
   5107         count  = varintToUint((u8**)data);
   5108         sBytesPushBuffer(&B, *data, count);
   5109         *data += count;
   5110         sArrayPushTiny(array, (smallt *) B);
   5111         // stop unpacking when packCount == 0
   5112         packCount--;
   5113         if (!packCount) inPack = false;
   5114         break;
   5115       case UNIFORM_DICT:
   5116         d = NULL;
   5117         uniformDictNetDeserial(&d, data, ctx, /*packed=*/false);
   5118         sArrayPushTiny(array, (smallt *) d);
   5119         break;
   5120       case UNIFORM_ARRAY:
   5121         a = NULL;
   5122         uniformArrayNetDeserial(&a, data, ctx, /*packed=*/false);
   5123         sArrayPushTiny(array, (smallt *) a);
   5124         break;
   5125     }
   5126   }
   5127 }
   5128 
   5129 internal void uniformArrayNetDeserial(sArrayt **array, u8 **data, contextt *ctx, bool packed) {
   5130   sUndefinedt *u = NULL;
   5131   sBoolt *bo = NULL;
   5132   double *D = NULL;
   5133   sDoublet *Do = NULL;
   5134   sDictt *d = NULL;
   5135   sIntt *io = NULL;
   5136   char *s = NULL;
   5137   sStringt *so = NULL;
   5138   sArrayt *a = NULL;
   5139   sBytest *B = NULL;
   5140   uint32_t count;
   5141   uint32_t arrayCount;
   5142   u8 type;
   5143 
   5144   if (packed) {
   5145     type = (**data) & 0xF;
   5146     arrayCount = netTypeVarintToUint(data);
   5147   }
   5148   else {
   5149     if (ctx->nibble == lowNbl) {
   5150       type = (**data) >> 4;
   5151       (*data)++;
   5152       arrayCount = varintToUint(data);
   5153     }
   5154     else {
   5155       readTypeInHighNbl;
   5156       type = (**data) & 0xF;
   5157       arrayCount = netTypeVarintToUint(data);
   5158     }
   5159   }
   5160 
   5161   if (!arrayCount) {
   5162     *array = allocSArray();;
   5163     ret;
   5164   }
   5165 
   5166   switch(type) {
   5167     case S_UNDEFINED:
   5168       loop(arrayCount) {
   5169         u = allocSUndefined();
   5170         sArrayPushTiny(array, (smallt *) u);
   5171       }
   5172       break;
   5173     case S_BOOL:
   5174       loop(arrayCount) {
   5175         if (!ctx->boolAddr) {
   5176           read8bPackedBool;
   5177           ctx->boolShift = 0;
   5178         }
   5179         if (ctx->boolShift == 8) {
   5180           read8bPackedBool;
   5181           bo = allocSBool((*ctx->boolAddr) & 0x1);
   5182         }
   5183         else {
   5184           bo = allocSBool((*ctx->boolAddr) & (0x1 << (ctx->boolShift++)));
   5185         }
   5186         sArrayPushTiny(array, (smallt *) bo);
   5187       }
   5188       break;
   5189     case S_DICT:
   5190       loop(arrayCount) {
   5191         d = NULL;
   5192         dictNetDeserial(&d, data, ctx, /*packed=*/true);
   5193         sArrayPushTiny(array, (smallt *) d);
   5194       }
   5195       break;
   5196     case S_DOUBLE:
   5197       loop(arrayCount) {
   5198         D      = (double *)(*data);
   5199         *data += sizeof(double);
   5200         Do     = allocSDouble(*D);
   5201         sArrayPushTiny(array, (smallt *) Do);
   5202       }
   5203       break;
   5204     case S_INT:
   5205       loop(arrayCount) {
   5206         u64 v = varintToUint(data);
   5207         v     = (v >> 1) ^ (~(v & 1) + 1);
   5208         io    = allocSInt(v);
   5209         sArrayPushTiny(array, (smallt *) io);
   5210       }
   5211       break;
   5212     case S_STRING:
   5213       loop(arrayCount) {
   5214         s      = (char *)(*data);
   5215         *data += strlen(s)+1;
   5216         so     = allocSStringTiny(s);
   5217         sArrayPushTiny(array, (smallt *) so);
   5218       }
   5219       break;
   5220     case S_ARRAY:
   5221       loop(arrayCount) {
   5222         a = NULL;
   5223         arrayNetDeserial(&a, data, ctx, /*packed=*/true);
   5224         sArrayPushTiny(array, (smallt *) a);
   5225       }
   5226       break;
   5227     case S_BYTES:
   5228       loop(arrayCount) {
   5229         B      = allocSBytes();
   5230         count  = varintToUint((u8**)data);
   5231         sBytesPushBuffer(&B, *data, count);
   5232         *data += count;
   5233         sArrayPushTiny(array, (smallt *) B);
   5234       }
   5235       break;
   5236     case UNIFORM_DICT:
   5237       loop(arrayCount) {
   5238         d = NULL;
   5239         uniformDictNetDeserial(&d, data, ctx, /*packed=*/true);
   5240         sArrayPushTiny(array, (smallt *) d);
   5241       }
   5242       break;
   5243     case UNIFORM_ARRAY:
   5244       loop(arrayCount) {
   5245         a = NULL;
   5246         uniformArrayNetDeserial(&a, data, ctx, /*packed=*/true);
   5247         sArrayPushTiny(array, (smallt *) a);
   5248       }
   5249       break;
   5250   }
   5251 }
   5252 
   5253 internal smallJsont* deserialNetSerial(smallJsont *self, smallBytest *data) {
   5254 
   5255   if (!data or !data->B or !data->B->count) {
   5256     ret self;
   5257   }
   5258 
   5259   smallt *o = netDeserial(data->B);
   5260 
   5261   if (!o) {
   5262     ret self;
   5263   }
   5264 
   5265   freeG(self);
   5266 
   5267   setsoG(self, o);
   5268 
   5269   ret self;
   5270 }
   5271 
   5272 // vim: set expandtab ts=2 sw=2:
   5273 
   5274 bool checkLibsheepyVersionNetSerial(const char *currentLibsheepyVersion) {
   5275   return eqG(currentLibsheepyVersion, LIBSHEEPY_VERSION);
   5276 }
   5277