netSerial

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