aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkartofen <mladenovnasko0@gmail.com>2025-04-02 01:15:23 +0300
committerkartofen <mladenovnasko0@gmail.com>2025-04-02 01:15:23 +0300
commit40618c2ff1c18815741888674cc76c8ddc486300 (patch)
tree707cd01dd35d9197e7627966a7ab84b393a0b1dc
parent5fba9e4d7492ca07d619999120b42495cf3df7c7 (diff)
made building better and added README, everything else is very unfinished
-rw-r--r--README.md20
-rw-r--r--build.ninja9
-rw-r--r--msgpack.c369
-rw-r--r--msgpack.h24
-rw-r--r--ninja.m466
-rw-r--r--test.c111
6 files changed, 368 insertions, 231 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8209d24
--- /dev/null
+++ b/README.md
@@ -0,0 +1,20 @@
+# MSGPACK
+
+This is a simple implementation of the MessagePack specification (`spec.md` in the tree)
+This library uses on dynamic allocations
+
+### Usage
+
+See the api in `msgpack.h`, it is self-explanatory
+
+### Building
+
+This project use ninja and m4 macros, use `ninja` to build, with
+options like:
+`shared`, `static`, `header` for bulding to a usable library and
+`test`to run the unit tests.
+
+To change paths and presets using `ninja configure` with an
+appropriate environment variable:
+`BIN=<path>` to set the output directory
+`PROD=1` to use the non-debug flags
diff --git a/build.ninja b/build.ninja
index 2f1d0b0..de4f42d 100644
--- a/build.ninja
+++ b/build.ninja
@@ -1,6 +1,7 @@
-rule gen
+rule regen
command = m4 ninja.m4 > build.ninja
- generator = 1
+ generator=1
-build bootstrap: gen
-default bootstrap
+build force: phony
+build build.ninja: regen | force
+
diff --git a/msgpack.c b/msgpack.c
index f20a54d..2e6b57f 100644
--- a/msgpack.c
+++ b/msgpack.c
@@ -1,86 +1,98 @@
#include "msgpack.h"
-#include <endian.h>
-
-#define TO_I8(b) (*(int8_t*)(b))
-#define TO_I16(b) ((int16_t)be16toh(*(uint16_t *)(b)))
-#define TO_I32(b) ((int32_t)be32toh(*(uint32_t *)(b)))
-#define TO_I64(b) ((int64_t)be64toh(*(uint64_t *)(b)))
-
-#define TO_U8(b) (*(uint8_t*)(b))
-#define TO_U16(b) ((uint16_t)be16toh(*(uint16_t *)(b)))
-#define TO_U32(b) ((uint32_t)be32toh(*(uint32_t *)(b)))
-#define TO_U64(b) ((uint64_t)be64toh(*(uint64_t *)(b)))
-
-#define ENOUGH_BYTES(pack, n, on_fail) if((pack)->size < (n)) { on_fail; }
+#include <endian.h> // endianness
+#include <string.h> // memcpy
+
+// TODO: fix all these
+#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_PINT8(b) (*(int8_t*)(b))
+#define H_PINT16(b) ((int16_t)htobe16((int16_t)(b)))
+#define H_PINT32(b) ((int32_t)htobe32((int32_t)(b)))
+#define H_PINT64(b) ((int64_t)htobe64((int64_t)(b)))
+
+#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(0x00, 0x7F) \
+ X(0x80, 0x8F) \
+ X(0x90, 0x9F) \
+ X(0xA0, 0xBF) \
X(0xE0, 0xFF)
-#define FORMAT_NIL(X) \
- X(0xC1, FMT_UNKNOWN, MSGPACK_UNKNOWN, ;, 1, 0) \
- X(0xC0, FMT_NIL, MSGPACK_NIL, ;, 1, 0)
-
-// byte, fmt, type, _, offset, length, data
-#define FORMAT_BOOL(X) \
- X(0xC2, FMT_BOOL_TRUE, MSGPACK_BOOL, ;, 1, 0, true) \
- X(0xC3, FMT_BOOL_FALSE, MSGPACK_BOOL, ;, 1, 0, false)
-
-// byte, fmt, type, subtype, offset, length, data
-#define FORMAT_INT(X) \
- X(0x00, FMT_FIX_UINT, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 0, TO_U8(pack->bin)) \
- X(0XE0, FMT_FIX_INT, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 0, TO_I8(pack->bin)) \
- X(0xCC, FMT_U8, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 1, TO_U8(pack->bin+1)) \
- X(0xCD, FMT_U16, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 2, TO_U16(pack->bin+1)) \
- X(0xCE, FMT_U32, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 4, TO_U32(pack->bin+1)) \
- X(0xCF, FMT_U64, MSGPACK_INT, MSGPACK_INT_UNSIGNED, 1, 8, TO_U64(pack->bin+1)) \
- X(0xD0, FMT_I8, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 1, TO_I8(pack->bin+1)) \
- X(0xD1, FMT_I16, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 2, TO_I16(pack->bin+1)) \
- X(0xD2, FMT_I32, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 4, TO_I32(pack->bin+1)) \
- X(0xD3, FMT_I64, MSGPACK_INT, MSGPACK_INT_SIGNED, 1, 8, TO_I64(pack->bin+1))
-
-// byte, fmt, type, subtype, offset, length, data
-#define FORMAT_FLOAT(X) \
- X(0xCA, FMT_FLOAT, MSGPACK_FLOAT, MSGPACK_FLOAT_32, 1, 4, TO_U32(pack->bin+1)) \
- X(0xCB, FMT_DOUBLE, MSGPACK_FLOAT, MSGPACK_FLOAT_64, 1, 8, TO_U64(pack->bin+1))
-
-// 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] & 0x1F) \
- X(0xC4, FMT_BIN8, MSGPACK_RAW, MSGPACK_RAW_BIN, 1, pack->bin[1]) \
- X(0xC5, FMT_BIN16, MSGPACK_RAW, MSGPACK_RAW_BIN, 3, TO_U16(pack->bin+1)) \
- X(0xC6, FMT_BIN32, MSGPACK_RAW, MSGPACK_RAW_BIN, 5, TO_U32(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, TO_U16(pack->bin+1)) \
- X(0xDB, FMT_STR32, MSGPACK_RAW, MSGPACK_RAW_STRING, 5, TO_U32(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, TO_U16(pack->bin+1), 3, elements_length(pack, fmt)) \
- X(0xDD, FMT_ARRAY32, MSGPACK_ARRAY, TO_U32(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 * (TO_U16(pack->bin+1)), 3, elements_length(pack, fmt)) \
- X(0xDF, FMT_MAP32, MSGPACK_MAP, 2 * (TO_U32(pack->bin+1)), 5, elements_length(pack, fmt))
-
-#define FORMAT_EXT(X)
-
-#define FORMATS(X) \
- FORMAT_NIL (X) \
- FORMAT_BOOL (X) \
- FORMAT_INT (X) \
- FORMAT_FLOAT(X) \
- FORMAT_RAW (X) \
- FORMAT_ARRAY(X) \
- FORMAT_MAP (X) \
- FORMAT_EXT (X)
-
-#define EXPAND(X) X
+// 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,
@@ -92,131 +104,198 @@ enum msgpack_fmt {
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 enum msgpack_fmt pack_fmt(const msgpack_t *pack);
// 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 ERROR(type, err) ERROR2(type, err, 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 CHECK_PACK(type, pack) \
- if(!(pack) || !(pack)->bin || (pack)->size == 0) \
- return ERROR((type), MSGPACK_ERROR_INVALID_PACK)
+#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 CHECK_ARG(type, m) \
- if(!(m)) \
- return ERROR((type), MSGPACK_ERROR_INVALID_ARGUMENT)
+#define FMT_FOR_READ(pack, type, subtype, m) pack_fmt(pack)
+#define FMT_FOR_WRITE(pack, type, subtype, m) data_fmt(type, subtype, m)
-#define MOVE_PACK(pack, sz) \
- do { \
- pack->bin += (sz); \
- pack->size -= (sz); \
- } while(0)
+// --- function composition --- //
-#define READ_FUNCTION(type) \
+// these will be shadowed unless missing in parameters
+const void * const m = (void *)1;
+const enum msgpack_type subtype;
+
+#define COMPOSE_FUNCTION(op, type) \
{ \
- CHECK_PACK(MSGPACK_##type, pack); \
- CHECK_ARG (MSGPACK_##type, m); \
+ 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 = pack_fmt(pack); \
+ enum msgpack_fmt fmt = \
+ FMT_FOR_##op(pack, MSGPACK_##type, subtype, m); \
\
switch(fmt) { \
- FORMAT_##type(X_READ_##type) \
+ FORMAT_##type(X_##type##_##op) \
default: \
return ERROR2(MSGPACK_##type, MSGPACK_ERROR_WRONG_TYPE, \
fmt_to_type[fmt]); \
} \
}
-#define X_READ_BOOL(_byte, x_fmt, x_type, _, x_offset, x_length, x_data) \
- case x_fmt: \
- MOVE_PACK(pack, (x_offset)); \
- *m = x_data; \
+#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 X_READ_INT(_byte, x_fmt, x_type, x_subtype, x_offset, x_length, x_data) \
- case x_fmt: \
- ENOUGH_BYTES(pack, (x_offset) + (x_length), \
- return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \
- MOVE_PACK(pack, (x_offset) + (x_length)); \
- \
- m->u = x_data; \
+#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)
+
+#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);
-#define X_READ_FLOAT(...) X_READ_INT(__VA_ARGS__)
-
-#define X_READ_RAW(_byte, x_fmt, x_type, x_subtype, x_offset, x_length) \
- case x_fmt: \
- ENOUGH_BYTES(pack, (x_offset), \
- return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \
- ENOUGH_BYTES(pack, (size_t)(x_offset) + (x_length), \
- return ERROR2(x_type, MSGPACK_ERROR_UNEXPECTED_END, x_subtype)); \
- MOVE_PACK(pack, (x_offset) + (x_length)); \
- \
- m->bin = pack->bin + (x_offset); \
- m->size = (x_length); \
- return SUCCESS2(x_type, x_subtype);
-#define X_READ_EXT(...) X_READ_RAW(__VA_ARGS__)
+// --- api implemention --- //
-#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)); \
- MOVE_PACK(pack, (x_offset)); \
- \
- *m = x_elements; \
- return SUCCESS(x_type);
+#define X_BOOL_READ(...) MAKE_X_BOOL(READ, __VA_ARGS__)
+#define X_INT_READ(...) MAKE_X_INT(READ, __VA_ARGS__)
-#define X_READ_MAP(...) X_READ_ARRAY(__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_bool (msgpack_t *pack, bool *m) READ_FUNCTION(BOOL)
-int msgpack_read_int (msgpack_t *pack, union mp_int *m) READ_FUNCTION(INT)
-int msgpack_read_float (msgpack_t *pack, union mp_float *m) READ_FUNCTION(FLOAT)
-
-int msgpack_read_raw (msgpack_t *pack, struct mp_bin *m) READ_FUNCTION(RAW)
+// 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) READ_FUNCTION(EXT)
+// 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) READ_FUNCTION(ARRAY)
-int msgpack_read_map (msgpack_t *pack, size_t *m) READ_FUNCTION(MAP)
+// 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);
-int msgpack_write_bool (msgpack_t *pack, const bool *m);
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_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);
-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(const msgpack_t *pack)
+static enum msgpack_fmt pack_fmt(msgpack_t *pack)
{
- ENOUGH_BYTES(pack, 1, return 0);
uint8_t byte = pack->bin[0];
- RANGES(X_MASK_RANGE){};
+ 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_high, x_range_low) \
+ 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); \
diff --git a/msgpack.h b/msgpack.h
index 8bb4514..ab3a643 100644
--- a/msgpack.h
+++ b/msgpack.h
@@ -62,7 +62,6 @@ union mp_int {
union mp_float {
float f;
double d;
- uint64_t u;
};
struct mp_bin {
@@ -70,16 +69,16 @@ struct mp_bin {
size_t size;
};
-struct mp_array {
- msgpack_t *members;
- size_t length;
-};
+// struct mp_array {
+// msgpack_t *members;
+// size_t length;
+// };
-struct mp_map {
- msgpack_t *keys;
- msgpack_t *members;
- size_t length;
-};
+// struct mp_map {
+// msgpack_t *keys;
+// msgpack_t *members;
+// size_t length;
+// };
struct mp_timestamp {
// ...
@@ -114,8 +113,8 @@ struct mp_timestamp {
enum msgpack_type;
int msgpack_read_nil (msgpack_t *pack);
-int msgpack_read_int (msgpack_t *pack, union mp_int *m);
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);
@@ -129,8 +128,9 @@ int msgpack_read_map (msgpack_t *pack, size_t *length);
// int msgpack_read_map2 (const msgpack_t *pack, struct mp_map *m);
-int msgpack_write_int (msgpack_t *pack, const union mp_int *m, enum msgpack_type subtype);
+int msgpack_write_nil (msgpack_t *pack);
int msgpack_write_bool (msgpack_t *pack, const bool *m);
+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);
diff --git a/ninja.m4 b/ninja.m4
index 77812a0..2f2a01a 100644
--- a/ninja.m4
+++ b/ninja.m4
@@ -1,10 +1,22 @@
+divert(-1)
+
changequote([,])
-cflags = ifdef([PROD], [], [-std=c99 -Wall -Wextra -g -D_DEFAULT_SOURCE])
-bin = bin
-m4flags =
+define([getenv], [
+ define([$1], [esyscmd([echo -n $$1])])
+ ifelse($1, , [undefine([$1])])
+])
+
+getenv([PROD])
+getenv([BIN])
+
+divert(0)
+
+cflags = ifdef([PROD], [], [-Wall -Wextra -g]) -std=c99 -D_DEFAULT_SOURCE
+bin = ifdef([BIN], [BIN], [bin])
+m4flags =
-# build as library
+# building
rule cc
command = gcc $cflags $in -o $out
@@ -15,8 +27,11 @@ rule ar
command = ar rcs $out $in
rule m4
command = m4 $m4flags $in > $out
-
-build $bin/msgpack.o: obj msgpack.c
+rule cpy
+ command = cp $in $out
+
+build $bin/msgpack.o: obj msgpack.c
+build $bin/msgpack.h: cpy msgpack.h
build $bin/libmsgpack.a: ar $bin/msgpack.o
build $bin/libmsgpack.so: cc $bin/msgpack.o
@@ -26,40 +41,31 @@ build $bin/libmsgpack.h: m4 msgpack.h | msgpack.c
# testing
+build $bin/test: cc msgpack.c test.c
+
rule valgrind
command = valgrind -s --leak-check=full --show-leak-kinds=all $in
-
-build $bin/test.o: obj test.c
-build $bin/test: cc msgpack.c $bin/test.o
# named targets
-rule cpy
- command = cp $in $out
-build $bin/msgpack.h: cpy msgpack.h
+rule ninja_clean
+ command = ninja -t clean
-build static: phony $bin/libmsgpack.a | $bin/msgpack.h
-build shared: phony $bin/libmsgpack.so | $bin/msgpack.h
+build static: phony $bin/libmsgpack.a $bin/msgpack.h
+build shared: phony $bin/libmsgpack.so $bin/msgpack.h
build header: phony $bin/libmsgpack.h
-build test: valgrind $bin/test
-ifdef([PROD], [default header], [default test])
+build test: valgrind $bin/test
+build clean: ninja_clean
+
+default ifdef([PROD], [static], [test])
# regeneration
-rule gen
- command = m4 $m4flags ninja.m4 > build.ninja
- generator = 1
+rule regen
+ command = m4 ninja.m4 > build.ninja
+ generator=1
-build build.ninja: gen | ninja.m4
+build build.ninja: regen ninja.m4
+build configure: regen
-rule _clean
- command = ninja -t clean
-build clean: _clean
-
-ifdef([PROD], [dnl
-build dev: gen | clean
-], [dnl
-build prod: gen | clean
- m4flags = -D [PROD]
-])
diff --git a/test.c b/test.c
index b8fd68b..96a4527 100644
--- a/test.c
+++ b/test.c
@@ -1,23 +1,25 @@
#include <stdio.h>
+#include <string.h>
#include "msgpack.h"
#define _IN " "
-#define assert(c) assert2(c, ;)
-#define assert2(c, b) \
+#define _assert1(c) _assert2(c, ;)
+#define _assert2(c, b) _assert3(#c, c, b)
+#define _assert3(n, c, b) \
do { \
if(!(c)) { \
- fprintf(stderr, "Assertion error '%s' in %s:%d\n", #c, __FILE__, __LINE__); \
+ printf("Assertion error '%s' in %s:%d\n", n, __FILE__, __LINE__); \
b; \
failed_asserts++; \
} \
} while (0);
-#define logvar(v, fmt) logvar2(v, v, fmt)
-#define logvar2(n, v, fmt) printf(_IN #n" = "fmt"\n", v)
+#define _logvar2(v, fmt) _logvar3(v, v, fmt)
+#define _logvar3(n, v, fmt) printf(_IN #n" = "fmt"\n", v)
-#define logbuf(b, l, fmt) logbuf(b, b, l, fmt)
-#define logbuf2(n, b, l, fmt) \
+#define _logbuf3(b, l, fmt) _logbuf4(b, b, l, fmt)
+#define _logbuf4(n, b, l, fmt) \
do { \
printf(_IN #n" = { "fmt, b[0]); \
for(size_t i = 1; i < l; i++) printf(", "fmt, b[i]); \
@@ -25,14 +27,19 @@
} while(0)
-#define logbytes(b, l) logbytes(b, b, l)
-#define logbytes2(n, b, l) logbuf2(n, b, l, "0x%hhx")
+#define OVERLOAD_MACRO_4(_1, _2, _3, _4, NAME, ...) NAME
+#define assert(...) OVERLOAD_MACRO_4(__VA_ARGS__, _, _assert3, _assert2, _assert1) (__VA_ARGS__)
+#define logvar(...) OVERLOAD_MACRO_4(__VA_ARGS__, _, _logvar3, _logvar2, _) (__VA_ARGS__)
+#define logbuf(...) OVERLOAD_MACRO_4(__VA_ARGS__, _logbuf4, _logbuf3, _, _) (__VA_ARGS__)
+#define logbytes(...) logbuf(__VA_ARGS__, "0x%hhx")
-#define make_template(call, body) \
- do { \
- int prev_failed_asserts = failed_asserts; \
- call; \
- assert2(prev_failed_asserts == failed_asserts, body); \
+#define make_template(call, body) \
+ do { \
+ int prev_failed_asserts = failed_asserts; \
+ call; \
+ assert("Failed Test Condition", \
+ prev_failed_asserts == failed_asserts, \
+ body); \
} while(0)
static int passed_test_counter;
@@ -42,7 +49,7 @@ static int failed_asserts;
int test_bool();
int test_int();
-#define CHECK(test) \
+#define TEST(test) \
do { \
if(test) { \
printf("[FAILED] "#test"\n"); \
@@ -53,12 +60,10 @@ int test_int();
} \
} while(0)
-// the functions in main form a test suite
-
int main(void)
{
- CHECK(test_bool());
- // CHECK(test_int());
+ TEST(test_bool());
+ TEST(test_int());
printf("\n------------------------------\n");
printf("PASSED %d/%d tests, (%.1f%%)\n",
@@ -69,27 +74,43 @@ int main(void)
return 0;
}
+#define BODY_SUCCESS_1(type) \
+ { \
+ assert(t == type, \
+ logvar(t, msgpack_type_string[t], "%s")); \
+ }
+
+#define BODY_FAILED_1(t, e, a) \
+ { \
+ assert("Failed Call", 0, ;); \
+ logvar(t, msgpack_type_string[t], "%s"); \
+ logvar(e, msgpack_error_string[e], "%s"); \
+ if(e == MSGPACK_ERROR_WRONG_TYPE) \
+ logvar(a, msgpack_type_string[a], "%s"); \
+ else logvar(a, "%hhx"); \
+ return; \
+ }
+
+
void bool_1(uint8_t *buf, size_t size, bool value)
{
- bool b;
- MSGPACK_CHECK2(msgpack_read_bool(&msgpack_init(buf, size, NULL), &b), (t, e, a),
- {
- assert2(t == MSGPACK_BOOL, logvar2(t, msgpack_type_string[t], "%s"));
- }, {
- (void)e;
- (void)a;
- assert(0);
- // log variables
- return;
- });
-
- assert2(b == value, logvar(b, "%d"));
+ uint8_t b[1];
+ bool v;
+
+ MSGPACK_CHECK2(msgpack_read_bool(&msgpack_init(buf, size, NULL), &v),
+ (t, e, a), BODY_SUCCESS_1(MSGPACK_BOOL), BODY_FAILED_1(t, e, a));
+ assert(v == value, logvar(v, "%d"));
+
+ MSGPACK_CHECK2(msgpack_write_bool(&msgpack_init(b, size, NULL), &value),
+ (t, e, a), BODY_SUCCESS_1(MSGPACK_BOOL), BODY_FAILED_1(t, e, a));
+ assert(memcmp(buf, b, size) == 0, logbytes(b, size));
}
#define bool_template(n, _buf, _value) \
make_template(bool_##n(_buf, sizeof(_buf), _value), { \
- logbytes2(buf, _buf, sizeof(_buf)); \
- logvar2(value, _value, "%d"); \
+ logbytes(buf, _buf, sizeof(_buf)); \
+ logvar(value, _value, "%d"); \
+ printf("\n"); \
}); \
int test_bool()
@@ -98,13 +119,23 @@ int test_bool()
bool_template(1, (uint8_t []){0xC2}, true);
bool_template(1, (uint8_t []){0xC3}, false);
- bool_template(1, (uint8_t []){0xC1}, false);
return failed_asserts;
}
-// void test_int()
-// {
-// char buf[] = {0xD3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01};
-// char buf[] = {0xCC, 0xFF};
-// }
+#define int_template(n, _buf, _value) \
+ make_template(bool_##n(_buf, sizeof(_buf), _value), { \
+ logbytes(buf, _buf, sizeof(_buf)); \
+ logvar(value, _value, "%d"); \
+ printf("\n"); \
+ }); \
+
+int test_int()
+{
+ failed_asserts = 0;
+
+ // char buf[] = {0xD3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01};
+ // char buf[] = {0xCC, 0xFF};
+
+ return failed_asserts;
+}