From 6da856f2942ca8cca860b8ea5b00ec85bbc60fd9 Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Tue, 3 Apr 2018 18:23:07 +0900 Subject: [PATCH] Add convenient functions for MessagePack --- include/groonga/Makefile.am | 1 + include/groonga/msgpack.h | 48 +++++++ lib/c_sources.am | 1 + lib/grn_msgpack.h | 24 ++++ lib/msgpack.c | 266 ++++++++++++++++++++++++++++++++++++ 5 files changed, 340 insertions(+) create mode 100644 include/groonga/msgpack.h create mode 100644 lib/msgpack.c diff --git a/include/groonga/Makefile.am b/include/groonga/Makefile.am index 3c5018fd8d..d8e115a2ae 100644 --- a/include/groonga/Makefile.am +++ b/include/groonga/Makefile.am @@ -19,6 +19,7 @@ groonga_include_HEADERS = \ groonga.h \ id.h \ ii.h \ + msgpack.h \ obj.h \ operator.h \ option.h \ diff --git a/include/groonga/msgpack.h b/include/groonga/msgpack.h new file mode 100644 index 0000000000..16484ecf82 --- /dev/null +++ b/include/groonga/msgpack.h @@ -0,0 +1,48 @@ +/* -*- c-basic-offset: 2 -*- */ +/* + Copyright(C) 2018 Brazil + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define GRN_MSGPACK_OBJECT_EXT_TIME 0 + +grn_rc grn_msgpack_pack_raw(grn_ctx *ctx, + msgpack_packer *packer, + const char *value, + unsigned int value_size, + grn_id value_domain); + +grn_rc grn_msgpack_pack(grn_ctx *ctx, + msgpack_packer *packer, + grn_obj *value); + +grn_rc grn_msgpack_unpack_array(grn_ctx *ctx, + msgpack_object_array *array, + grn_obj *vector); +int64_t grn_msgpack_unpack_ext_time(grn_ctx *ctx, + msgpack_object_ext *ext); + +#ifdef __cplusplus +} +#endif diff --git a/lib/c_sources.am b/lib/c_sources.am index 090e174f74..4b0c674472 100644 --- a/lib/c_sources.am +++ b/lib/c_sources.am @@ -50,6 +50,7 @@ libgroonga_c_sources = \ grn_logger.h \ mrb.c \ grn_mrb.h \ + msgpack.c \ grn_msgpack.h \ nfkc.c \ grn_nfkc.h \ diff --git a/lib/grn_msgpack.h b/lib/grn_msgpack.h index c153d83bba..256ce09f79 100644 --- a/lib/grn_msgpack.h +++ b/lib/grn_msgpack.h @@ -18,6 +18,8 @@ #pragma once +#include "grn.h" + #ifdef GRN_WITH_MESSAGE_PACK # include @@ -35,6 +37,9 @@ typedef unsigned int msgpack_size_t; # define MSGPACK_OBJECT_STR_SIZE(object) (object)->via.raw.size # define MSGPACK_OBJECT_FLOAT_VALUE(object) (object)->via.dec + +# define MSGPACK_UNPACKER_NEXT(unpacker, unpacked) \ + msgpack_unpacker_next((unpacker), (unpacked)) # else /* MSGPACK_VERSION_MAJOR < 1 */ typedef size_t msgpack_size_t; @@ -42,5 +47,24 @@ typedef size_t msgpack_size_t; # define MSGPACK_OBJECT_STR_SIZE(object) (object)->via.str.size # define MSGPACK_OBJECT_FLOAT_VALUE(object) (object)->via.f64 + +# define MSGPACK_UNPACKER_NEXT(unpacker, unpacked) \ + msgpack_unpacker_next((unpacker), (unpacked)) == MSGPACK_UNPACK_SUCCESS # endif /* MSGPACK_VERSION_MAJOR < 1 */ + +grn_rc grn_msgpack_pack_raw_internal(grn_ctx *ctx, + msgpack_packer *packer, + const char *value, + unsigned int value_size, + grn_id value_domain); +grn_rc grn_msgpack_pack_internal(grn_ctx *ctx, + msgpack_packer *packer, + grn_obj *value); +grn_rc grn_msgpack_unpack_array_internal(grn_ctx *ctx, + msgpack_object_array *array, + grn_obj *vector); +int64_t grn_msgpack_unpack_ext_time_internal(grn_ctx *ctx, + msgpack_object_ext *ext); + + #endif /* GRN_WITH_MESSAGE_PACK */ diff --git a/lib/msgpack.c b/lib/msgpack.c new file mode 100644 index 0000000000..70fb272766 --- /dev/null +++ b/lib/msgpack.c @@ -0,0 +1,266 @@ +/* -*- c-basic-offset: 2 -*- */ +/* + Copyright(C) 2018 Brazil + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "grn_ctx.h" +#include "grn_db.h" +#include "grn_msgpack.h" + +#ifdef GRN_WITH_MESSAGE_PACK + +# include + +grn_rc +grn_msgpack_pack_raw_internal(grn_ctx *ctx, + msgpack_packer *packer, + const char *value, + unsigned int value_size, + grn_id value_domain) +{ + if (value_size == 0) { + msgpack_pack_nil(packer); + return ctx->rc; + } + + switch (value_domain) { + case GRN_DB_VOID : + msgpack_pack_nil(packer); + break; + case GRN_DB_BOOL : + if (*((grn_bool *)value)) { + msgpack_pack_true(packer); + } else { + msgpack_pack_false(packer); + } + break; + case GRN_DB_INT8 : + msgpack_pack_int8(packer, *((int8_t *)(value))); + break; + case GRN_DB_UINT8 : + msgpack_pack_uint8(packer, *((uint8_t *)(value))); + break; + case GRN_DB_INT16 : + msgpack_pack_int16(packer, *((int16_t *)(value))); + break; + case GRN_DB_UINT16 : + msgpack_pack_uint16(packer, *((uint16_t *)(value))); + break; + case GRN_DB_INT32 : + msgpack_pack_int32(packer, *((int32_t *)(value))); + break; + case GRN_DB_UINT32 : + msgpack_pack_uint32(packer, *((uint32_t *)(value))); + break; + case GRN_DB_INT64 : + msgpack_pack_int64(packer, *((int64_t *)(value))); + break; + case GRN_DB_UINT64 : + msgpack_pack_uint64(packer, *((uint64_t *)(value))); + break; + case GRN_DB_FLOAT : + msgpack_pack_double(packer, *((double *)(value))); + break; + case GRN_DB_TIME : + /* TODO: Use timestamp time in spec. */ + msgpack_pack_ext(packer, sizeof(int64_t), GRN_MSGPACK_OBJECT_EXT_TIME); + msgpack_pack_ext_body(packer, value, sizeof(int64_t)); + break; + case GRN_DB_SHORT_TEXT : + case GRN_DB_TEXT : + case GRN_DB_LONG_TEXT : + msgpack_pack_str(packer, value_size); + msgpack_pack_str_body(packer, value, value_size); + break; + default : + { + char domain_name[GRN_TABLE_MAX_KEY_SIZE]; + int domain_name_size; + + domain_name_size = grn_table_get_key(ctx, + grn_ctx_db(ctx), + value_domain, + domain_name, + sizeof(domain_name)); + ERR(GRN_FUNCTION_NOT_IMPLEMENTED, + "[msgpack][pack] unsupported type: <%.*s>", + domain_name_size, domain_name); + } + break; + } + + return ctx->rc; +} + +grn_rc +grn_msgpack_pack_internal(grn_ctx *ctx, + msgpack_packer *packer, + grn_obj *value) +{ + if (value) { + return grn_msgpack_pack_raw_internal(ctx, + packer, + GRN_BULK_HEAD(value), + GRN_BULK_VSIZE(value), + value->header.domain); + } else { + return grn_msgpack_pack_raw_internal(ctx, + packer, + NULL, + 0, + GRN_DB_VOID); + } +} + +grn_rc +grn_msgpack_unpack_array_internal(grn_ctx *ctx, + msgpack_object_array *array, + grn_obj *vector) +{ + int32_t i; + + grn_obj_ensure_vector(ctx, vector); + + for (i = 0; i < array->size && ctx->rc == GRN_SUCCESS; i++) { + msgpack_object *element; + + element = &(array->ptr[i]); + switch (element->type) { + case MSGPACK_OBJECT_BOOLEAN : + { + grn_bool value = element->via.boolean; + grn_vector_add_element(ctx, + vector, + (const char *)&value, + sizeof(grn_bool), + 0, + GRN_DB_BOOL); + } + break; + case MSGPACK_OBJECT_POSITIVE_INTEGER : + grn_vector_add_element(ctx, + vector, + (const char *)&(element->via.i64), + sizeof(int64_t), + 0, + GRN_DB_INT64); + break; + case MSGPACK_OBJECT_NEGATIVE_INTEGER : + grn_vector_add_element(ctx, + vector, + (const char *)&(element->via.u64), + sizeof(uint64_t), + 0, + GRN_DB_UINT64); + break; + case MSGPACK_OBJECT_FLOAT : + grn_vector_add_element(ctx, + vector, + (const char *)&(MSGPACK_OBJECT_FLOAT_VALUE(element)), + sizeof(double), + 0, + GRN_DB_FLOAT); + break; + case MSGPACK_OBJECT_STR : + grn_vector_add_element(ctx, + vector, + MSGPACK_OBJECT_STR_PTR(element), + MSGPACK_OBJECT_STR_SIZE(element), + 0, + GRN_DB_TEXT); + break; + case MSGPACK_OBJECT_EXT : + if (element->via.ext.type == GRN_MSGPACK_OBJECT_EXT_TIME) { + grn_vector_add_element(ctx, + vector, + element->via.ext.ptr, + sizeof(int64_t), + 0, + GRN_DB_TIME); + } else { + ERR(GRN_INVALID_ARGUMENT, + "[msgpack] unknown extension type: <%u>", + element->via.ext.type); + } + break; + default : + ERR(GRN_INVALID_ARGUMENT, + "[msgpack] unexpected element type: <%#x>", + element->type); + break; + } + } + + return ctx->rc; +} + +int64_t +grn_msgpack_unpack_ext_time_internal(grn_ctx *ctx, + msgpack_object_ext *ext) +{ + if (ext->type == GRN_MSGPACK_OBJECT_EXT_TIME) { + return *(int64_t *)(ext->ptr); + } else { + ERR(GRN_INVALID_ARGUMENT, + "[msgpack] time extension type must be <%u>: <%u>", + GRN_MSGPACK_OBJECT_EXT_TIME, + ext->type); + return 0; + } +} + +grn_rc +grn_msgpack_pack_raw(grn_ctx *ctx, + msgpack_packer *packer, + const char *value, + unsigned int value_size, + grn_id value_domain) +{ + GRN_API_ENTER; + grn_msgpack_pack_raw_internal(ctx, packer, value, value_size, value_domain); + GRN_API_RETURN(ctx->rc); +} + +grn_rc +grn_msgpack_pack(grn_ctx *ctx, + msgpack_packer *packer, + grn_obj *value) +{ + GRN_API_ENTER; + grn_msgpack_pack_internal(ctx, packer, value); + GRN_API_RETURN(ctx->rc); +} + +grn_rc +grn_msgpack_unpack_array(grn_ctx *ctx, + msgpack_object_array *array, + grn_obj *vector) +{ + GRN_API_ENTER; + grn_msgpack_unpack_array_internal(ctx, array, vector); + GRN_API_RETURN(ctx->rc); +} + +int64_t +grn_msgpack_unpack_ext_time(grn_ctx *ctx, + msgpack_object_ext *ext) +{ + int64_t time; + GRN_API_ENTER; + time = grn_msgpack_unpack_ext_time_internal(ctx, ext); + GRN_API_RETURN(time); +} +#endif /* GRN_WITH_MESSAGE_PACK */