From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp56.i.mail.ru (smtp56.i.mail.ru [217.69.128.36]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id BC74E45BE2E for ; Tue, 12 May 2020 02:46:06 +0300 (MSK) From: Vladislav Shpilevoy Date: Tue, 12 May 2020 01:46:02 +0200 Message-Id: <1b15d2ad18263ed060088aa4f7e105b574c07ffa.1589240001.git.v.shpilevoy@tarantool.org> In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH msgpuck 2/2] Make MP_EXT mp_snprint() and mp_fprint() customizable List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: tarantool-patches@dev.tarantool.org, gorcunov@gmail.com, sergepetrenko@tarantool.org, korablev@tarantool.org MP_EXT in these functions was skipped and printed as 'undefined'. In Tarantool there are already 3 extensions - decimals, UUID, errors. It is time to make them being nicely printed too. The patch makes it possible via virtual MP_EXT serializer, which by default does the same as before. But in Tarantool is substituted with correct printer for the mentioned extensions. Part of https://github.com/tarantool/tarantool/issues/4719 --- msgpuck.c | 31 ++++++++++++++++--- msgpuck.h | 50 ++++++++++++++++++++++++++++++ test/msgpuck.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 159 insertions(+), 5 deletions(-) diff --git a/msgpuck.c b/msgpuck.c index 7ea86e8..1ee234b 100644 --- a/msgpuck.c +++ b/msgpuck.c @@ -33,6 +33,26 @@ #define MP_LIBRARY 1 #include "msgpuck.h" +int +mp_fprint_ext_default(FILE *file, const char **data, int depth) +{ + (void) depth; + mp_next(data); + return fprintf(file, "undefined"); +} + +int +mp_snprint_ext_default(char *buf, int size, const char **data, int depth) +{ + (void) depth; + mp_next(data); + return snprintf(buf, size, "undefined"); +} + +mp_fprint_ext_f mp_fprint_ext = mp_fprint_ext_default; + +mp_snprint_ext_f mp_snprint_ext = mp_snprint_ext_default; + size_t mp_vformat(char *data, size_t data_size, const char *format, va_list vl) { @@ -316,8 +336,7 @@ mp_format(char *data, size_t data_size, const char *format, ...) PRINTF("%lg", mp_decode_double(data)); \ break; \ case MP_EXT: \ - mp_next(data); \ - PRINTF("undefined"); \ + PRINT_EXT(data); \ break; \ default: \ mp_unreachable(); \ @@ -325,7 +344,7 @@ mp_format(char *data, size_t data_size, const char *format, ...) } \ } -static int +int mp_fprint_recursion(FILE *file, const char **data, int depth) { int total_bytes = 0; @@ -335,12 +354,14 @@ mp_fprint_recursion(FILE *file, const char **data, int depth) return -1; \ total_bytes += bytes; \ } while (0) +#define PRINT_EXT(...) HANDLE(mp_fprint_ext, __VA_ARGS__, depth) #define PRINT(...) HANDLE(fprintf, __VA_ARGS__) #define SELF(...) HANDLE(mp_fprint_recursion, __VA_ARGS__, depth) MP_PRINT(SELF, PRINT) #undef HANDLE #undef SELF #undef PRINT +#undef PRINT_EXT return total_bytes; } @@ -353,7 +374,7 @@ mp_fprint(FILE *file, const char *data) return res; } -static int +int mp_snprint_recursion(char *buf, int size, const char **data, int depth) { int total_bytes = 0; @@ -371,12 +392,14 @@ mp_snprint_recursion(char *buf, int size, const char **data, int depth) size = 0; \ } \ } while (0) +#define PRINT_EXT(...) HANDLE(mp_snprint_ext, __VA_ARGS__, depth) #define PRINT(...) HANDLE(snprintf, __VA_ARGS__) #define SELF(...) HANDLE(mp_snprint_recursion, __VA_ARGS__, depth) MP_PRINT(SELF, PRINT) #undef HANDLE #undef SELF #undef PRINT +#undef PRINT_EXT return total_bytes; } #undef MP_PRINT diff --git a/msgpuck.h b/msgpuck.h index 5dfbbd9..91c7693 100644 --- a/msgpuck.h +++ b/msgpuck.h @@ -980,6 +980,30 @@ mp_vformat(char *data, size_t data_size, const char *format, va_list args); int mp_fprint(FILE *file, const char *data); +/** + * \brief Print MsgPack data to \a file using JSON-like format. + * Works exactly like \sa mp_fprint(), but allows to specify max + * depth, and changes \a data parameter. Intended to be used for + * MsgPack serialization recursion. + */ +int +mp_fprint_recursion(FILE *file, const char **data, int depth); + +typedef int (*mp_fprint_ext_f)(FILE *file, const char **data, int depth); + +/** + * \brief Function called when need to serialize MP_EXT into a + * file. + */ +extern mp_fprint_ext_f mp_fprint_ext; + +/** + * \brief Default MP_EXT serializer into a file. Skips the object, + * ignores all the other arguments, and writes 'undefined'. + */ +int +mp_fprint_ext_default(FILE *file, const char **data, int depth); + /** * \brief format MsgPack data to \a buf using JSON-like format. * \sa mp_fprint() @@ -997,6 +1021,32 @@ mp_fprint(FILE *file, const char *data); int mp_snprint(char *buf, int size, const char *data); +/** + * \brief Format MsgPack data to \a buf using JSON-like format. + * Works exactly like \sa mp_snprint(), but allows to specify max + * depth, and changes \a data parameter. Intended to be used for + * MsgPack serialization recursion. + */ +int +mp_snprint_recursion(char *buf, int size, const char **data, int depth); + +typedef int (*mp_snprint_ext_f)(char *buf, int size, const char **data, + int depth); + +/** + * \brief Function called when need to serialize MP_EXT into a + * string. + */ +extern mp_snprint_ext_f mp_snprint_ext; + +/** + * \brief Default MP_EXT serializer into a string. Skips the + * object, ignores all the other arguments, and prints + * 'undefined'. + */ +int +mp_snprint_ext_default(char *buf, int size, const char **data, int depth); + /** * \brief Check that \a cur buffer has enough bytes to decode a string header * \param cur buffer diff --git a/test/msgpuck.c b/test/msgpuck.c index ecc2b26..1d8c726 100644 --- a/test/msgpuck.c +++ b/test/msgpuck.c @@ -969,6 +969,86 @@ test_mp_print() return check_plan(); } +enum mp_ext_test_type { + MP_EXT_TEST_PLAIN, + MP_EXT_TEST_MSGPACK, +}; + +static int +mp_fprint_ext_test(FILE *file, const char **data, int depth) +{ + int8_t type; + uint32_t len = mp_decode_extl(data, &type); + const char *ext = *data; + *data += len; + switch(type) { + case MP_EXT_TEST_PLAIN: + return fprintf(file, "%.*s", len, ext); + case MP_EXT_TEST_MSGPACK: + return mp_fprint_recursion(file, &ext, depth); + } + return fprintf(file, "undefined"); +} + +static int +mp_snprint_ext_test(char *buf, int size, const char **data, int depth) +{ + int8_t type; + uint32_t len = mp_decode_extl(data, &type); + const char *ext = *data; + *data += len; + switch(type) { + case MP_EXT_TEST_PLAIN: + return snprintf(buf, size, "%.*s", len, ext); + case MP_EXT_TEST_MSGPACK: + return mp_snprint_recursion(buf, size, &ext, depth); + } + return snprintf(buf, size, "undefined"); +} + +static int +test_mp_print_ext(void) +{ + plan(5); + header(); + mp_snprint_ext = mp_snprint_ext_test; + mp_fprint_ext = mp_fprint_ext_test; + + char *pos = buf; + const char *plain = "plain-str"; + size_t plain_len = strlen(plain); + pos = mp_encode_array(pos, 4); + pos = mp_encode_uint(pos, 100); + pos = mp_encode_ext(pos, MP_EXT_TEST_PLAIN, plain, plain_len); + pos = mp_encode_extl(pos, MP_EXT_TEST_MSGPACK, + mp_sizeof_str(plain_len)); + pos = mp_encode_str(pos, plain, plain_len); + pos = mp_encode_uint(pos, 200); + + int size = mp_snprint(NULL, 0, buf); + int real_size = mp_snprint(str, sizeof(str), buf); + is(size, real_size, "mp_snrpint size match"); + const char *expected = "[100, plain-str, \"plain-str\", 200]"; + is(strcmp(str, expected), 0, "str is correct"); + + FILE *tmpf = tmpfile(); + if (tmpf == NULL) + abort(); + real_size = mp_fprint(tmpf, buf); + is(size, real_size, "mp_fprint size match"); + rewind(tmpf); + real_size = (int) fread(str, 1, sizeof(str), tmpf); + is(real_size, size, "mp_fprint written correct number of bytes"); + str[real_size] = 0; + is(strcmp(str, expected), 0, "str is correct"); + fclose(tmpf); + + mp_snprint_ext = mp_snprint_ext_default; + mp_fprint_ext = mp_fprint_ext_default; + footer(); + return check_plan(); +} + int test_mp_check() { @@ -1226,7 +1306,7 @@ test_overflow() int main() { - plan(22); + plan(23); test_uints(); test_ints(); test_bools(); @@ -1246,6 +1326,7 @@ int main() test_compare_uints(); test_format(); test_mp_print(); + test_mp_print_ext(); test_mp_check(); test_numbers(); test_overflow(); -- 2.21.1 (Apple Git-122.3)