aboutsummaryrefslogtreecommitdiff
path: root/msgpack.h
diff options
context:
space:
mode:
Diffstat (limited to 'msgpack.h')
-rw-r--r--msgpack.h242
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