diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..13f3d0c --- /dev/null +++ b/.clangd @@ -0,0 +1,6 @@ +CompileFlags: + Add: [ -Wall, -I/home/aaron/Projects/empack/src ] +InlayHints: + Enabled: false +Completion: + ArgumentLists: None diff --git a/src/empack.c b/src/empack.c index 24b8dd8..e1c513c 100644 --- a/src/empack.c +++ b/src/empack.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -713,6 +714,217 @@ empack_print(empack_t *empack, return (ret); } + + + +static empack_status_e +_empack_allocate_packed_object(empack_t *empack, empack_obj_t **obj) +{ + if (empack->parent == NULL) { + (*obj) = &empack->root; + empack->parent = &empack->root; + return EMPACK_STATUS_WANT_MORE; + } + + while (1) { + if (empack->parent == NULL) { + return EMPACK_STATUS_EXTRA; + } + + if (EMPACK_IS_MAP(empack->parent->type)) { + empack_map_t *pmap = &empack->parent->val.map; + + if (pmap->pairs_parsed == pmap->pair_count) { + empack->parent = empack->parent->parent; + continue; + } + + /* we set the key's type to error to indicate whether it's been + * filled out already or not */ + if (pmap->pairs[pmap->pairs_parsed].key.type == EMPACK_TYPE_ERROR) { + (*obj) = &pmap->pairs[pmap->pairs_parsed].key; + } else { + (*obj) = &pmap->pairs[pmap->pairs_parsed].value; + pmap->pairs_parsed++; + } + + break; + } else if (EMPACK_IS_ARRAY(empack->parent->type)) { + empack_array_t *parr = &empack->parent->val.array; + + if (parr->objects_parsed == parr->object_count) { + empack->parent = empack->parent->parent; + continue; + } + + (*obj) = &parr->objects[parr->objects_parsed]; + parr->objects_parsed++; + + break; + } else { + /* this shouldn't be possible */ + return EMPACK_STATUS_ERROR; + } + } + + return EMPACK_STATUS_WANT_MORE; +} + + + +empack_status_e +empack_pack_map(empack_t *empack, uint32_t pair_count, empack_obj_t **obj) +{ + if (pair_count > UINT16_MAX) { + return empack_pack_map32(empack, pair_count, obj); + } else if (pair_count > EMPACK_FIXMAP_MAX) { + return empack_pack_map16(empack, pair_count, obj); + } else { + return empack_pack_fixmap(empack, pair_count, obj); + } +} + +empack_status_e +_empack_init_map(empack_t *empack, empack_obj_t *obj, uint32_t pair_count) +{ + empack_map_t *map = &obj->val.map; + map->pair_count = pair_count; + + if (pair_count > 0) { + map->pairs = empack_allocate(empack, sizeof(*map->pairs) * pair_count); + if (map->pairs == NULL) { + return EMPACK_STATUS_NOMEM; + } + } + + /* mark all of the key's types as error to assist in figuring out what's + * been packed or not */ + for (uint32_t i = 0; i < pair_count; i++) { + map->pairs[i].key.type = EMPACK_TYPE_ERROR; + } + + if (pair_count == 0) { + return EMPACK_STATUS_COMPLETE; + } else { + return EMPACK_STATUS_WANT_MORE; + } +} + +empack_status_e +empack_pack_fixmap(empack_t *empack, uint8_t pair_count, empack_obj_t **obj) +{ + empack_status_e ret; + empack_obj_t *new_obj; + + if (pair_count > EMPACK_FIXMAP_MAX) { + return EMPACK_STATUS_INVALID; + } + + ret = _empack_allocate_packed_object(empack, &new_obj); + if (ret != EMPACK_STATUS_WANT_MORE) { + return (ret); + } + + if (obj) { + *obj = new_obj; + } + + new_obj->type = EMPACK_TYPE_FIXMAP; + return _empack_init_map(empack, new_obj, pair_count); +} + +empack_status_e +empack_pack_map16(empack_t *empack, uint16_t pair_count, empack_obj_t **obj) +{ + empack_status_e ret; + empack_obj_t *new_obj; + + if (pair_count > UINT16_MAX) { + return EMPACK_STATUS_INVALID; + } + + ret = _empack_allocate_packed_object(empack, &new_obj); + if (ret != EMPACK_STATUS_WANT_MORE) { + return (ret); + } + + if (obj) { + *obj = new_obj; + } + + new_obj->type = EMPACK_TYPE_MAP16; + return _empack_init_map(empack, new_obj, pair_count); +} + +empack_status_e +empack_pack_map32(empack_t *empack, uint32_t pair_count, empack_obj_t **obj) +{ + empack_status_e ret; + empack_obj_t *new_obj; + + if (pair_count > UINT32_MAX) { + return EMPACK_STATUS_INVALID; + } + + ret = _empack_allocate_packed_object(empack, &new_obj); + if (ret != EMPACK_STATUS_WANT_MORE) { + return (ret); + } + + if (obj) { + *obj = new_obj; + } + + new_obj->type = EMPACK_TYPE_MAP32; + return _empack_init_map(empack, new_obj, pair_count); +} + + + +empack_status_e +empack_pack_array(empack_t *empack, uint32_t obj_count, empack_obj_t **obj) +{ + if (obj_count > UINT16_MAX) { + return empack_pack_array32(empack, obj_count, obj); + } else if (obj_count > EMPACK_FIXARRAY_MAX) { + return empack_pack_array16(empack, obj_count, obj); + } else { + return empack_pack_fixarray(empack, obj_count, obj); + } +} + +empack_status_e +_empack_init_array(empack_t *empack, empack_obj_t *obj, uint32_t obj_count) +{ + empack_array_t *array = &obj->val.array; + array->object_count = obj_count; + + if (obj_count > 0) { + array->objects = empack_allocate(empack, sizeof(*array->objects) * obj_count); + if (array->objects == NULL) { + return EMPACK_STATUS_NOMEM; + } + + return EMPACK_STATUS_WANT_MORE; + } else { + return EMPACK_STATUS_COMPLETE; + } +} + +empack_status_e +empack_pack_fixarray(empack_t *empack, uint8_t obj_count, empack_obj_t **obj) +{ + +} + +empack_status_e empack_pack_array16(empack_t *empack, uint16_t obj_count, empack_obj_t **obj); + +empack_status_e empack_pack_array32(empack_t *empack, uint32_t obj_count, empack_obj_t **obj); + + + + + static void * empack_allocate(empack_t *empack, uint32_t size) { diff --git a/src/empack.h b/src/empack.h index 330fb90..4988b80 100644 --- a/src/empack.h +++ b/src/empack.h @@ -117,6 +117,8 @@ typedef enum empack_status_enum { * amount of memory required to fully parse the supplied Msgpack buffer */ EMPACK_STATUS_NOMEM, + /** An invalid value has been passed in while constructing a messagepack tree */ + EMPACK_STATUS_INVALID, /** Generic error while parsing */ EMPACK_STATUS_ERROR, } empack_status_e; @@ -209,7 +211,7 @@ struct empack_map_pair_struct { }; struct empack_struct { - /** Root object of the Msgpack object tree, filled out during parsing */ + /** Root object of the Msgpack object tree, filled out during parsing/packing */ empack_obj_t root; /** Memory arena empack can use to construct the object tree */ void *arena; @@ -217,6 +219,7 @@ struct empack_struct { uint32_t arena_sz; /** How much of the memory arena is used */ uint32_t arena_used; + empack_obj_t *parent; }; /** Macro for whether the given type is a map */ @@ -294,4 +297,89 @@ uint32_t empack_print(empack_t *empack, void *arg, const char *indent); +/** + * Given a fully construct or parsed empack struct, dump the equivalent Msgpack + * bytes via the provided write function callback. + * + * @param empack Empack struct to dump + * @param write_func Write function callback + * @param arg User argument for write_func + * + * @returns Number of bytes written + */ +uint32_t empack_dump(empack_t *empack, + void (*write_func)(const uint8_t *buf, uint32_t buflen, void *arg), + void *arg); + +/** + * Pack a map object, selecting the minimum required map type depending on the + * number of pairs. + * + * @param empack Empack struct to pack into + * @param pair_count Number of key-value pairs should end up in this map + * @param obj Optional return argument to get a pointer to the newly created object + * + * @returns An EMPACK_STATUS_* value + */ +empack_status_e empack_pack_map(empack_t *empack, uint32_t pair_count, empack_obj_t **obj); + +/** + * Pack a fixmap object + * + * @param empack Empack struct to pack into + * @param pair_count Number of key-value pairs should end up in this map + * @param obj Optional return argument to get a pointer to the newly created object + * + * @returns An EMPACK_STATUS_* value + */ +empack_status_e empack_pack_fixmap(empack_t *empack, uint8_t pair_count, empack_obj_t **obj); + +empack_status_e empack_pack_map16(empack_t *empack, uint16_t pair_count, empack_obj_t **obj); + +empack_status_e empack_pack_map32(empack_t *empack, uint32_t pair_count, empack_obj_t **obj); + + + +empack_status_e empack_pack_array(empack_t *empack, uint32_t obj_count, empack_obj_t **obj); + +empack_status_e empack_pack_fixarray(empack_t *empack, uint8_t obj_count, empack_obj_t **obj); + +empack_status_e empack_pack_array16(empack_t *empack, uint16_t obj_count, empack_obj_t **obj); + +empack_status_e empack_pack_array32(empack_t *empack, uint32_t obj_count, empack_obj_t **obj); + + + +/** + * Pack an integer into the empack tree, choosing the smallest object type that + * the value will fit into. + * + * @param empack Empack struct to pack into + * @param val Integer value to pack + * @param obj Optional return argument to get a pointer to the newly created object + * + * @returns An EMPACK_STATUS_* value + */ +empack_status_e empack_pack_int(empack_t *empack, long val, empack_obj_t **obj); + +empack_status_e empack_pack_pos_fixint(empack_t *empack, uint8_t val, empack_obj_t **obj); + +empack_status_e empack_pack_uint8(empack_t *empack, uint8_t val, empack_obj_t **obj); + +empack_status_e empack_pack_uint16(empack_t *empack, uint16_t val, empack_obj_t **obj); + +empack_status_e empack_pack_uint32(empack_t *empack, uint32_t val, empack_obj_t **obj); + +empack_status_e empack_pack_uint64(empack_t *empack, uint64_t val, empack_obj_t **obj); + +empack_status_e empack_pack_neg_fixint(empack_t *empack, int8_t val, empack_obj_t **obj); + +empack_status_e empack_pack_int8(empack_t *empack, int8_t val, empack_obj_t **obj); + +empack_status_e empack_pack_int16(empack_t *empack, int16_t val, empack_obj_t **obj); + +empack_status_e empack_pack_int32(empack_t *empack, int32_t val, empack_obj_t **obj); + +empack_status_e empack_pack_int64(empack_t *empack, int64_t val, empack_obj_t **obj); + #endif /* _EMPACK_H_ */