#ifndef MSGPACK_H #define MSGPACK_H #include #include #include /* -- Data structures -- * * These structs are used for decoding the MessagePack format. * They follow the format specification and their members are as * straight-forward as possible. * * They are meant to be stack allocated, and be passed as pointers * to the appropriate function and be filled. This library does no * memory allocations by default (except one function that returns * a generic and needs a function ptr to an allocator to be passed * as an argument, see 'msgpack_read(...)') * * msgpack_t: * - stores the current substring and its size * - can use a membuf to cache the length of * it's substrings * - created with 'msgpack_init' macro, by pasing * the binary string, size, and optional membuf * (set to null if not using it) * * struct msgpack_membuf: * - used to store substring length * - passed down other 'msgpack_t's * in arrays and maps * - created with 'membuf_init' macro by * passing the starting address of the * binary string as an 'uintptr_t' and * an already allocated size_t *, with * as many members as bytes in the bin * string * * ... * */ typedef struct mp_msgpack { uint8_t *bin; size_t size; // struct mp_membuf { // uintptr_t offset; // size_t *buf; // } *membuf; } msgpack_t; #define msgpack_init(bin, size, membuf) \ ((msgpack_t){(bin), (size)}) // ((msgpack_t){(bin), (size), (membuf)}) union mp_int { int64_t i; uint64_t u; }; union mp_float { float f; double d; }; struct mp_bin { uint8_t* bin; size_t size; }; // struct mp_array { // msgpack_t *members; // size_t length; // }; // struct mp_map { // msgpack_t *keys; // msgpack_t *members; // size_t length; // }; struct mp_timestamp { // ... }; /* -- API for this library -- * * Arguments: * - pack is a ptr to a struct that hold the msgpack binary * - m is a ptr to allocated memory that will be filled by the function * * Return value: * - The [2-0] bits are the type of the * read value (useful for msgpack_read); * - If an error is encountered, the sign bit * is set, and; * - The [5-3] bits are the error code. * * Use the MSGPACK_CHECK functions to easily * manage errors. * * Example: * 0b|1|...|00000000|001|101 * | | | | | * err | byte info | type[5] * | | * not important error[1] * */ enum msgpack_type; int msgpack_read_nil (msgpack_t *pack); // NOT IMPLEMENTED int msgpack_read_bool (msgpack_t *pack, bool *m); int msgpack_read_int (msgpack_t *pack, union mp_int *m); int msgpack_read_float (msgpack_t *pack, union mp_float *m); int msgpack_read_raw (msgpack_t *pack, struct mp_bin *m); // int msgpack_read_raw_cpy (msgpack_t *pack, struct mp_bin *m); int msgpack_read_ext (msgpack_t *pack, struct mp_bin *m); // NOT IMPLEMENTED // int msgpack_read_ext_cpy (msgpack_t *pack, struct mp_bin *m); int msgpack_read_array (msgpack_t *pack, size_t *length); int msgpack_read_map (msgpack_t *pack, size_t *length); // int msgpack_read_array2 (const msgpack_t *pack, struct mp_array *m); // int msgpack_read_map2 (const msgpack_t *pack, struct mp_map *m); int msgpack_write_nil (msgpack_t *pack); int msgpack_write_bool (msgpack_t *pack, const bool *m); // NOT IMPLEMENTED int msgpack_write_int (msgpack_t *pack, const union mp_int *m, enum msgpack_type subtype); 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); // NOT IMPLEMENTED int msgpack_write_map (msgpack_t *pack, const size_t *m); int msgpack_write_array (msgpack_t *pack, const size_t *m); /* -- MessagePack Types -- * * These types are defined by the messagepack specification * and X-Marcros are used to generate enums and arrays with * their string counterparts. * * There are subtypes for some of the main types, * which are not present in the specificiation, but * are can be useful for the client * */ #define MSGPACK_TYPES(X) \ X(MSGPACK_NIL) \ X(MSGPACK_INT) \ X(MSGPACK_BOOL) \ X(MSGPACK_FLOAT) \ X(MSGPACK_RAW) \ X(MSGPACK_ARRAY) \ X(MSGPACK_MAP) \ X(MSGPACK_EXT) \ #define MSGPACK_SUBTYPES(X) \ X(MSGPACK_UNKNOWN) \ X(MSGPACK_INT_SIGNED) \ X(MSGPACK_INT_UNSIGNED) \ X(MSGPACK_FLOAT_32) \ X(MSGPACK_FLOAT_64) \ X(MSGPACK_RAW_STRING) \ X(MSGPACK_RAW_BIN) \ X(MSGPACK_EXT_TIMESTAMP) #define MSGPACK_ERRORS(X) \ X(MSGPACK_ERROR_UNKNOWN) \ X(MSGPACK_ERROR_INVALID_PACK) \ X(MSGPACK_ERROR_INVALID_ARGUMENT) \ X(MSGPACK_ERROR_WRONG_TYPE) \ X(MSGPACK_ERROR_UNSUFFICIENT_CAPACITY) \ X(MSGPACK_ERROR_UNEXPECTED_END) #define X_TO_ENUM(e) e, #define X_TO_STRING(e) [e] = #e, enum msgpack_type { MSGPACK_TYPES(X_TO_ENUM) MSGPACK_SUBTYPES(X_TO_ENUM) }; enum msgpack_error { MSGPACK_ERRORS(X_TO_ENUM) }; static const char * const msgpack_type_string[] = { MSGPACK_TYPES(X_TO_STRING) MSGPACK_SUBTYPES(X_TO_STRING) }; static const char * const msgpack_error_string[] = { MSGPACK_ERRORS(X_TO_STRING) }; /* -- Macros for error handling -- * * Argumnts: * - call is the function call to a msgpack_*** function; * - body_*** is a scope that is invoked upon error or success, * it uses the variable names from the 'arg' varible; * - arg is the name of the variables that hold the: * - msgpack type; * - msgpack error code; * - extra byte data, * which are extracted from the return value of the function call. * * Example: * MSGPACK_CHECK(msgpack_read_bool(&pack, &b), (t, e, a), { * if(e == MSGPACK_ERROR_WRONG_TYPE) { * err("msgpack: %s, expected type %s, but got type %s", * msgpack_error_string[e], * msgpack_type_string[a], * msgpack_type_string[t]); * } * }); * */ #define __EXPAND(...) __VA_ARGS__ #define __EXPAND_CALL(c, ...) c(__VA_ARGS__) #define __MSGPACK_CHECK(call, body_suc, body_err, type_var, err_var, rest_var) \ do { \ int __r = (call); \ int (type_var) = __r & 0x7; \ int (err_var) = (__r >> 3) & 0x7; \ int (rest_var) = (__r >> 6) & 0xFF; \ if(__r >= 0) { body_suc; } \ else { body_err; } \ } while(0) #define MSGPACK_CHECK(call, arg, body_err) \ __EXPAND_CALL(__MSGPACK_CHECK, call, ;, body_err, __EXPAND arg) #define MSGPACK_CHECK2(call, arg, body_suc, body_err) \ __EXPAND_CALL(__MSGPACK_CHECK, call, body_suc, body_err, __EXPAND arg) #endif