aboutsummaryrefslogtreecommitdiff
path: root/msgpack.c
blob: 70cd4637a59be9c9ad97f3ffdb68d6612060bb47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
#include "msgpack.h"
#include <endian.h>  // endianness
#include <string.h>  // memcpy

#define PINT8_H(p)  (*(int8_t*)(p))
#define PINT16_H(p) ((int16_t)be16toh(*(uint16_t *)(p)))
#define PINT32_H(p) ((int32_t)be32toh(*(uint32_t *)(p)))
#define PINT64_H(p) ((int64_t)be64toh(*(uint64_t *)(p)))

#define PUINT8_H(p)  (*(uint8_t*)(p))
#define PUINT16_H(p) (be16toh(*(uint16_t *)(p)))
#define PUINT32_H(p) (be32toh(*(uint32_t *)(p)))
#define PUINT64_H(p) (be64toh(*(uint64_t *)(p)))

#define H_UINT8(b)  ((uint8_t)b)
#define H_UINT16(b) ((uint16_t)htobe16((uint16_t)(b)))
#define H_UINT32(b) ((uint32_t)htobe32((uint32_t)(b)))
#define H_UINT64(b) ((uint64_t)htobe64((uint64_t)(b)))

#define H_UINT8_CPY(b, p)   (((uint8_t*)(p))[0]  = H_UINT8(b));
#define H_UINT16_CPY(b, p)  (((uint16_t*)(p))[0] = H_UINT16(b))
#define H_UINT32_CPY(b, p)  (((uint32_t*)(p))[0] = H_UINT32(b))
#define H_UINT64_CPY(b, p)  (((uint64_t*)(p))[0] = H_UINT64(b))

#define H_INT8_CPY(b, p)  H_UINT8_CPY(b, p)
#define H_INT16_CPY(b, p) H_UINT16_CPY(b, p)
#define H_INT32_CPY(b, p) H_UINT32_CPY(b, p)
#define H_INT64_CPY(b, p) H_UINT64_CPY(b, p)

// fix these
// #define F32_H(b) (*(float *) &be32toh(*(uint32_t *)(b)))
// #define F64_H(b) (*(double *)&be64toh(*(uint64_t *)(b)))
// #define H_F32(b) (*(float *) &htobe32(*(uint32_t *)(b)))
// #define H_F64(b) (*(double *)&htobe64(*(uint64_t *)(b)))

// range low, range high
#define RANGES(X) \
    X(0x00, 0x7F) \
    X(0x80, 0x8F) \
    X(0x90, 0x9F) \
    X(0xA0, 0xBF) \
    X(0xE0, 0xFF)

// byte, format, type
#define FORMAT_NIL(X) \
    X(0xC0, FMT_NIL,     MSGPACK_NIL)
#define FORMAT_UNKNOWN(X) \
    X(0xC1, FMT_UNKNOWN, MSGPACK_UNKNOWN)

// byte, format, type, data
#define FORMAT_BOOL(X)                           \
    X(0xC2, FMT_BOOL_TRUE,  MSGPACK_BOOL, true)  \
    X(0xC3, FMT_BOOL_FALSE, MSGPACK_BOOL, false)

// byte, format, type, subtype, offset, lengh, field, conv, range high, range low
#define FORMAT_INT(X)                                                                                \
    X(0x00, FMT_FIX_UINT, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 0, 1, u, UINT8,  0,         127)        \
    X(0XE0, FMT_FIX_INT,  MSGPACK_INT, MSGPACK_INT_SIGNED,   0, 1, i, INT8,   -32,       -1)         \
    X(0xCC, FMT_U8,       MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 1, u, UINT8,  0,         UINT8_MAX)  \
    X(0xCD, FMT_U16,      MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 2, u, UINT16, 0,         UINT16_MAX) \
    X(0xCE, FMT_U32,      MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 4, u, UINT32, 0,         UINT32_MAX) \
    X(0xCF, FMT_U64,      MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 8, u, UINT64, 0,         UINT64_MAX) \
    X(0xD0, FMT_I8,       MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 1, i, INT8,   INT8_MIN,  INT8_MAX)   \
    X(0xD1, FMT_I16,      MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 2, i, INT16,  INT16_MIN, INT16_MAX)  \
    X(0xD2, FMT_I32,      MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 4, i, INT32,  INT32_MIN, INT32_MAX)  \
    X(0xD3, FMT_I64,      MSGPACK_INT, MSGPACK_INT_SIGNED,   1, 8, i, INT64,  INT64_MIN, INT64_MAX)

// byte, format, type, subtype, offset, length, field, conv
#define FORMAT_FLOAT(X)                                                \
    X(0xCA, FMT_FLOAT,  MSGPACK_FLOAT, MSGPACK_FLOAT_32, 1, 4, f, F32) \
    X(0xCB, FMT_DOUBLE, MSGPACK_FLOAT, MSGPACK_FLOAT_64, 1, 8, d, F64)

// // byte, fmt, type, subtype, offset, length, data
// #define FORMAT_RAW(X)                                                               \
//     X(0xA0, FMT_FIX_STR,   MSGPACK_RAW, MSGPACK_RAW_STRING, 1, pack->bin[0] & 0x0F) \
//     X(0xC4, FMT_BIN8,      MSGPACK_RAW, MSGPACK_RAW_BIN,    1, pack->bin[1])        \
//     X(0xC5, FMT_BIN16,     MSGPACK_RAW, MSGPACK_RAW_BIN,    3, UINT16_H(pack->bin+1)) \
//     X(0xC6, FMT_BIN32,     MSGPACK_RAW, MSGPACK_RAW_BIN,    5, UINT32_H(pack->bin+1)) \
//     X(0xD9, FMT_STR8,      MSGPACK_RAW, MSGPACK_RAW_STRING, 1, pack->bin[1])        \
//     X(0xDA, FMT_STR16,     MSGPACK_RAW, MSGPACK_RAW_STRING, 3, UINT16_H(pack->bin+1)) \
//     X(0xDB, FMT_STR32,     MSGPACK_RAW, MSGPACK_RAW_STRING, 5, UINT32_H(pack->bin+1))

// // byte, fmt, type, elements, offset, lenght
// #define FORMAT_ARRAY(X) \
//     X(0x90, FMT_FIX_ARRAY, MSGPACK_ARRAY, pack->bin[0] & 0x0F,   1, elements_length(pack, fmt)) \
//     X(0xDC, FMT_ARRAY16,   MSGPACK_ARRAY, UINT16_H(pack->bin+1), 3, elements_length(pack, fmt)) \
//     X(0xDD, FMT_ARRAY32,   MSGPACK_ARRAY, UINT32_H(pack->bin+1), 5, elements_length(pack, fmt))
// #define FORMAT_MAP(X) \
//     X(0x80, FMT_FIX_MAP,   MSGPACK_MAP, 2 * (pack->bin[0] & 0x0F),   1, elements_length(pack, fmt)) \
//     X(0xDE, FMT_MAP16,     MSGPACK_MAP, 2 * (UINT16_H(pack->bin+1)), 3, elements_length(pack, fmt)) \
//     X(0xDF, FMT_MAP32,     MSGPACK_MAP, 2 * (UINT32_H(pack->bin+1)), 5, elements_length(pack, fmt))

// #define FORMAT_EXT(X)

#define FORMATS(X)    \
    FORMAT_NIL    (X) \
    FORMAT_UNKNOWN(X) \
    FORMAT_BOOL   (X) \
    FORMAT_INT    (X) \
    FORMAT_FLOAT  (X) \
    // FORMAT_RAW    (X) \
    // FORMAT_ARRAY  (X) \
    // FORMAT_MAP    (X) \
    // FORMAT_EXT    (X)

#define X_FMT_ENUM(_byte, fmt, ...)       fmt,
#define X_FMT_TYPE(_byte, fmt, type, ...) [fmt] = type,
#define X_BYTE_FMT( byte, fmt, ...)       [byte] = fmt,

enum msgpack_fmt {
    FORMATS(X_FMT_ENUM)
};

static const enum msgpack_type fmt_to_type[] = {
    FORMATS(X_FMT_TYPE)
};

static const enum msgpack_fmt byte_to_fmt[] = {
    FORMATS(X_BYTE_FMT)
};

// static size_t elements_length(msgpack_t *pack, enum msgpack_fmt fmt);
// static size_t pack_size(msgpack_t *pack);


// --- helper macros --- //

#define SUCCESS(type) SUCCESS2(type, 0)
#define SUCCESS2(type, rest) \
    (((rest) << 6) | (type))

#define ERROR(type, err) ERROR2(type, err, 0)
#define ERROR2(type, err, rest) \
    ((1 << (sizeof(int)*8-1))| ((rest) << 6) | ((err) << 3) | (type))

#define ENOUGH_BYTES(pack, n, on_fail) \
    if((pack)->size < (n)) { on_fail; }
#define MOVE_PACK(pack, sz)   \
    do {                      \
        (pack)->bin  += (sz); \
        (pack)->size -= (sz); \
    } while(0)

static enum msgpack_fmt pack_fmt(msgpack_t *pack);
static enum msgpack_fmt data_fmt(enum msgpack_type type, enum msgpack_type subtype, void *m);

#define FMT_FOR_READ(pack, type, subtype, m)  pack_fmt(pack)
#define FMT_FOR_WRITE(pack, type, subtype, m) data_fmt(type, subtype, m)

// --- function composition --- //

// these will be shadowed unless missing in parameters
const void * const m = (void *)1;
const enum msgpack_type subtype;

#define COMPOSE_FUNCTION(op, type)                                      \
    {                                                                   \
        if(!pack || !pack->bin || pack->size == 0)                      \
            return ERROR(MSGPACK_##type, MSGPACK_ERROR_INVALID_PACK);   \
        if(!m)                                                          \
            return ERROR(MSGPACK_##type, MSGPACK_ERROR_INVALID_ARGUMENT); \
                                                                        \
        enum msgpack_fmt fmt =                                          \
            FMT_FOR_##op(pack, MSGPACK_##type, subtype, m);             \
                                                                        \
        switch(fmt) {                                                   \
            FORMAT_##type(X_##type##_##op)                              \
        default:                                                        \
            return ERROR2(MSGPACK_##type, MSGPACK_ERROR_WRONG_TYPE,     \
                          fmt_to_type[fmt]);                            \
        }                                                               \
    }

#define OP_BOOL_READ(x_byte, pack, m, x_data) \
    *m = x_data
#define OP_BOOL_WRITE(x_byte, pack, m, x_data) \
    pack->bin[0] = x_byte

#define MAKE_X_BOOL(op, x_byte, x_fmt, x_type, x_data)  \
    case x_fmt:                                    \
        OP_BOOL_##op(x_byte, pack, m, x_data);     \
        MOVE_PACK(pack, 1);                        \
        return SUCCESS(x_type);

#define OP_INT_READ(_byte, ptr, value, x_conv) \
    value = P##x_conv##_H(ptr)
#define OP_INT_WRITE(x_byte, ptr, value, x_conv) \
    (ptr-1)[0] = x_byte;      /* temp fix*/      \
    H_##x_conv##_CPY((value), (ptr))

#define MAKE_X_INT(op, x_byte, x_fmt, x_type, x_subtype, x_offset, x_length, x_field, x_conv, ...) \
    case x_fmt:                                                                          \
        ENOUGH_BYTES(pack, (x_offset) + (x_length),                                      \
            return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype));             \
        OP_INT_##op(x_byte, pack->bin + (x_offset), m->x_field, x_conv);                 \
                                                                                         \
        MOVE_PACK(pack, (x_offset) + (x_length));                                        \
        return SUCCESS2(x_type, x_subtype);


// --- api implemention --- //

#define X_BOOL_READ(...)  MAKE_X_BOOL(READ, __VA_ARGS__)
#define X_INT_READ(...)  MAKE_X_INT(READ, __VA_ARGS__)

int msgpack_read_nil   (msgpack_t *pack);// COMPOSE_FUNCTION(READ, NIL)
int msgpack_read_bool  (msgpack_t *pack,        bool     *m) COMPOSE_FUNCTION(READ, BOOL)
int msgpack_read_int   (msgpack_t *pack, union  mp_int   *m) COMPOSE_FUNCTION(READ, INT)
// int msgpack_read_float (msgpack_t *pack, union  mp_float *m); COMPOSE_FUNCTION(READ, FLOAT)

// int msgpack_read_raw   (msgpack_t *pack, struct mp_bin  *m)  COMPOSE_FUNCTION(READ, RAW)
// int msgpack_read_raw_cpy (msgpack_t *pack, struct mp_bin *m);
// int msgpack_read_ext   (msgpack_t *pack, struct mp_bin  *m)  COMPOSE_FUNCTION(READ, EXT)
// int msgpack_read_ext_cpy (msgpack_t *pack, struct mp_bin *m);

// int msgpack_read_array (msgpack_t *pack, size_t *m)          COMPOSE_FUNCTION(READ, ARRAY)
// int msgpack_read_map   (msgpack_t *pack, size_t *m)          COMPOSE_FUNCTION(READ, MAP)
// int msgpack_read_array2  (const msgpack_t *pack, struct mp_array *m);
// int msgpack_read_map2    (const msgpack_t *pack, struct mp_map   *m);

#define X_BOOL_WRITE(...) MAKE_X_BOOL(WRITE, __VA_ARGS__)
#define X_INT_WRITE(...)  MAKE_X_INT(WRITE, __VA_ARGS__)
    
int msgpack_write_nil     (msgpack_t *pack);
int msgpack_write_bool    (msgpack_t *pack, const       bool     *m) COMPOSE_FUNCTION(WRITE, BOOL)
int msgpack_write_int     (msgpack_t *pack, const union mp_int   *m, enum msgpack_type subtype) COMPOSE_FUNCTION(WRITE, INT)
int msgpack_write_float   (msgpack_t *pack, const union mp_float *m, enum msgpack_type subtype);

// int msgpack_write_raw     (msgpack_t *pack, const struct mp_bin  *m, enum msgpack_type subtype);
// int msgpack_write_ext     (msgpack_t *pack, const struct mp_bin  *m, enum msgpack_type subtype);

// int msgpack_write_array   (msgpack_t *pack, const size_t *m);
// int msgpack_write_map     (msgpack_t *pack, const size_t *m);


// --- helpers --- //

#define X_MASK_RANGE(range_low, range_high)         \
    if(byte >= range_low && byte <= range_high)     \
        byte &= ~(uint8_t)(range_high-range_low);   \
    else                                            \

static enum msgpack_fmt pack_fmt(msgpack_t *pack)
{
    uint8_t byte = pack->bin[0];

    RANGES(X_MASK_RANGE);
    return byte_to_fmt[byte];
}

#define WRAP_FMT_BOOL(e) \
    case MSGPACK_BOOL: switch(*(bool *)m) {e; default: break; } break;
#define X_FMT_BOOL(_byte, x_fmt, x_type, x_data) \
    case x_data: return x_fmt;

#define WRAP_FMT_INT(e) \
    case MSGPACK_INT: e; break;
#define X_FMT_INT(_byte, x_fmt, x_type, x_subtype, _offset, _length, x_field, _conv, x_range_low, x_range_high) \
    if((x_subtype == subtype) &&                                        \
       (((union mp_int *)m)->x_field >= x_range_low) &&                 \
       (((union mp_int *)m)->x_field <= x_range_high))                  \
        return x_fmt;                                                   \
    else

static enum msgpack_fmt data_fmt(enum msgpack_type type, enum msgpack_type subtype, void *m)
{
    switch(type) {
        WRAP_FMT_BOOL(FORMAT_BOOL(X_FMT_BOOL))
        WRAP_FMT_INT(FORMAT_INT(X_FMT_INT))
    default: return FMT_UNKNOWN;
    }

    return FMT_UNKNOWN;
}



// #define X_FLOAT(...) X_INT(__VA_ARGS__)

// #define OP_RAW_READ(x_byte, pack, m, x_offset, x_length)                     \
//         m->bin = pack->bin + (x_offset);                                     \
//         m->size = (x_length);                                                \
        
// #define X_READ_RAW(op, x_byte, x_fmt, x_type, x_subtype, x_offset, x_length_expr) \
//     case x_fmt:                                                              \
//         ENOUGH_BYTES(pack, (x_offset),                                       \
//             return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \
//         size_t length = x_length_expr;                                       \
//         ENOUGH_BYTES(pack, (size_t)(x_offset) + (x_length),                  \
//             return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \
//         OP_RAW_##op(x_byte, pack, m, (x_offset), (x_length));                \
//                                                                              \
//         MOVE_PACK(pack, (x_offset) + (x_length));                            \
//         return SUCCESS2(x_type, x_subtype);

// #define X_READ_EXT(...) //X_READ_RAW(__VA_ARGS__)

// #define X_READ_ARRAY(_byte, x_fmt, x_type, x_elements, x_offset, _length)    \
//     case x_fmt:                                                              \
//         ENOUGH_BYTES(pack, (x_offset),                                       \
//             return ERROR(x_type, MSGPACK_ERROR_UNEXPECTED_END));             \
//         *m = x_elements;                                                     \
//                                                                              \
//         MOVE_PACK(pack, (x_offset));                                         \
//         return SUCCESS(x_type);

// #define X_READ_MAP(...) X_READ_ARRAY(__VA_ARGS__)



// #define X_COMPLEX_LENGTH(_byte, x_fmt, _type, x_elements, x_offset, x_length) \
//     case x_fmt: {                                 \
//         ENOUGH_BYTES(pack, (x_offset), return 0); \
//         offset   = (x_offset);                    \
//         elements = (x_elements);                  \
//     } break;

// static size_t elements_length(msgpack_t *pack, enum msgpack_fmt fmt)
// {
//     size_t offset   = 0;
//     size_t elements = 0;

//     switch(fmt) {
//         FORMAT_ARRAY(X_COMPLEX_LENGTH)
//         FORMAT_MAP(X_COMPLEX_LENGTH)
//     default: return 0;
//     }

//     for(size_t i = 0; i < elements; i++) {
//         msgpack_t new_pack = {pack->bin + offset,
//                               pack->size - offset};//, pack->membuf};
//         size_t len = pack_size(&new_pack);
//         if(len == 0) return 0;

//         offset += len;
//         ENOUGH_BYTES(pack, offset, return 0);
//     }

//     return offset;
// }

// #define X_PACK_SIZE(_byte, x_fmt, _type, _, x_offset, x_length, ...) \
//     case x_fmt: {                                 \
//         ENOUGH_BYTES(pack, (x_offset), return 0); \
//         offset = (x_offset);                      \
//         length = (x_length);                      \
//     } break;

// static size_t pack_size(msgpack_t *pack)
// {
//     enum msgpack_fmt fmt = pack_fmt(pack);

//     size_t offset = 0;
//     size_t length = 0;

//     switch(fmt) {
//         FORMATS(X_PACK_SIZE)
//     default: return 0;
//     }

//     if(fmt_to_type[fmt] == MSGPACK_ARRAY || fmt_to_type[fmt] == MSGPACK_MAP)
//         if(length == 0) return 0;

//     return offset + length;
// }