diff options
author | kartofen <mladenovnasko0@gmail.com> | 2025-03-24 03:08:00 +0200 |
---|---|---|
committer | kartofen <mladenovnasko0@gmail.com> | 2025-03-24 03:08:00 +0200 |
commit | d3598381289ac23217c472d5f48df3bea891ecf2 (patch) | |
tree | 5b249e2cd4348a28f00dc2404684dcf4be176c81 /msgpack.h |
first
Diffstat (limited to 'msgpack.h')
-rw-r--r-- | msgpack.h | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/msgpack.h b/msgpack.h new file mode 100644 index 0000000..fc3ab9a --- /dev/null +++ b/msgpack.h @@ -0,0 +1,242 @@ +#ifndef MSGPACK_H +#define MSGPACK_H + +#include <stddef.h> +#include <stdint.h> + +/* -- 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 { + char *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), (membuf)}) +#define membuf_init(uintptr_bin, size_t_buf) \ + ((struct mp_membuf){(offset), (buf)}) + +union mp_int { + int64_t i; + uint64_t u; +}; + +union mp_float { + float f; + double d; + uint64_t _u; +}; + +struct mp_array { + msgpack_t *members; + size_t length; +}; + +struct mp_map { + msgpack_t *keys; + msgpack_t *members; + size_t length; +}; + +struct mp_bin { + char* bin; + size_t size; +}; + +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] + * + */ + +int msgpack_read_int (const msgpack_t *pack, union mp_int *m); +int msgpack_read_bool (const msgpack_t *pack, int *m); +int msgpack_read_float (const msgpack_t *pack, union mp_float *m); + +int msgpack_read_raw (const msgpack_t *pack, struct mp_bin *m); +int msgpack_read_raw_cpy (const msgpack_t *pack, struct mp_bin *m); +int msgpack_read_ext (const msgpack_t *pack, struct mp_bin *m); +int msgpack_read_ext_cpy (const 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_int (msgpack_t *pack, const union mp_int *m, int subtype); +int msgpack_write_bool (msgpack_t *pack, const int *m); +int msgpack_write_float (msgpack_t *pack, const union mp_float *m, int subtype); + +int msgpack_write_raw (msgpack_t *pack, const struct mp_bin *m, int subtype); +int msgpack_write_ext (msgpack_t *pack, const struct mp_bin *m, int subtype); + +int msgpack_write_array (msgpack_t *pack, const size_t *length); +int msgpack_write_map (msgpack_t *pack, const size_t *length); + +/* -- 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) \ + X(MSGPACK_UNKNOWN) \ + +#define MSGPACK_SUBTYPES(X) \ + 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_WRONG_TYPE) \ + X(MSGPACK_ERROR_UNSUFFICIENT_CAPACITY) \ + X(MSGPACK_ERROR_UNEXPECTED_END) \ + X(MSGPACK_ERROR_INVALID_PACK) \ + X(MSGPACK_ERROR_INVALID_ARGUMENT) + +#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 __MSGPACK_CHECK_DEFER(...) __MSGPACK_CHECK(__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) \ + __MSGPACK_CHECK_DEFER(call, ;, body_err, __EXPAND arg) +#define MSGPACK_CHECK2(call, arg, body_suc, body_err) \ + __MSGPACK_CHECK_DEFER(call, body_suc, body_err, __EXPAND arg) + +#endif |