From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp47.i.mail.ru (smtp47.i.mail.ru [94.100.177.107]) (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 C5AEA4696C6 for ; Sat, 4 Apr 2020 02:03:11 +0300 (MSK) From: Serge Petrenko Date: Sat, 4 Apr 2020 02:02:51 +0300 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH 3/4] box: add MsgPack encoding/decoding for UUID List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: v.shpilevoy@tarantool.org Cc: tarantool-patches@dev.tarantool.org A special format for encoding UUIDs to MsgPack is introduced. It is supported by both lua and C encoders/decoders, and it is now possible to insert UUIDs into spaces, but only into unindexed fields without format for now. Prerequisite #4268 @TarantoolBot document Title: Internals: msgpack format for UUID UUID values share the MessagePack type with decimals: both use MP_EXT. A new subtype is introduced for UUIDs, MP_UUID = `0x02` UUID is encoded as follows: ``` +--------+---------+-----------+ | MP_EXT | MP_UUID | UuidValue | +--------+---------+-----------+ ``` Since UUID is 16 bytes in size, the header, MP_EXT, is always the same: `0xd8`. MP_UUID = `0x02` follows. The header is followed by the 16 bytes of the UuidValue. The total size of such a representation is 18 bytes, whereas storing uuids as strings requires from 34 (when '-'s are ommitted) to 38 bytes per UUID, giving a 2x space usage improvement. --- extra/exports | 3 + src/lib/core/CMakeLists.txt | 1 + src/lib/core/mp_extension_types.h | 2 + src/lib/core/mp_uuid.c | 75 +++++++++++++++++++++++ src/lib/core/mp_uuid.h | 90 ++++++++++++++++++++++++++++ src/lib/core/mpstream.c | 11 ++++ src/lib/core/mpstream.h | 5 ++ src/lib/msgpuck | 2 +- src/lua/msgpack.c | 27 +++++++-- src/lua/msgpackffi.lua | 14 +++++ src/lua/utils.c | 21 ++++++- src/lua/utils.h | 5 ++ src/lua/uuid.lua | 9 --- test/app-tap/lua/serializer_test.lua | 8 +++ test/app-tap/msgpackffi.test.lua | 3 +- test/app/msgpack.result | 21 +++++++ test/app/msgpack.test.lua | 13 ++++ test/app/uuid.result | 2 +- test/box/tuple.result | 81 +++++++++++++++++++++++++ test/box/tuple.test.lua | 25 ++++++++ test/unit/uuid.c | 24 +++++++- test/unit/uuid.result | 8 ++- third_party/lua-cjson/lua_cjson.c | 27 ++++++--- third_party/lua-yaml/lyaml.cc | 17 +++++- 24 files changed, 461 insertions(+), 33 deletions(-) create mode 100644 src/lib/core/mp_uuid.c create mode 100644 src/lib/core/mp_uuid.h diff --git a/extra/exports b/extra/exports index cbb5adcf4..9dcb6bdcb 100644 --- a/extra/exports +++ b/extra/exports @@ -63,11 +63,14 @@ crc32_calc mp_encode_double mp_encode_float mp_encode_decimal +mp_encode_uuid mp_decode_double mp_decode_float mp_decode_extl mp_sizeof_decimal +mp_sizeof_uuid decimal_unpack +uuid_unpack log_type say_set_log_level diff --git a/src/lib/core/CMakeLists.txt b/src/lib/core/CMakeLists.txt index 3f13ff904..44968c2c9 100644 --- a/src/lib/core/CMakeLists.txt +++ b/src/lib/core/CMakeLists.txt @@ -29,6 +29,7 @@ set(core_sources port.c decimal.c mp_decimal.c + mp_uuid.c ) if (TARGET_OS_NETBSD) diff --git a/src/lib/core/mp_extension_types.h b/src/lib/core/mp_extension_types.h index bc9873f68..7d42f212b 100644 --- a/src/lib/core/mp_extension_types.h +++ b/src/lib/core/mp_extension_types.h @@ -42,6 +42,8 @@ enum mp_extension_type { MP_UNKNOWN_EXTENSION = 0, MP_DECIMAL = 1, + MP_UUID = 2, + mp_extension_type_MAX, }; #endif diff --git a/src/lib/core/mp_uuid.c b/src/lib/core/mp_uuid.c new file mode 100644 index 000000000..5b0cc3f1a --- /dev/null +++ b/src/lib/core/mp_uuid.c @@ -0,0 +1,75 @@ +/* + * Copyright 2020, Tarantool AUTHORS, please see AUTHORS file. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mp_uuid.h" +#include "msgpuck.h" +#include "mp_extension_types.h" +#include "lib/uuid/tt_uuid.h" + +inline uint32_t +mp_sizeof_uuid() +{ + return mp_sizeof_ext(sizeof(struct tt_uuid)); +} + +struct tt_uuid * +uuid_unpack(const char **data, uint32_t len, struct tt_uuid *uuid) +{ + if (len != sizeof(*uuid)) + return NULL; + memcpy(uuid, *data, sizeof(*uuid)); + if (tt_uuid_validate(uuid) != 0) + return NULL; + *data += sizeof(*uuid); + return uuid; +} + +struct tt_uuid * +mp_decode_uuid(const char **data, struct tt_uuid *uuid) +{ + if (mp_typeof(**data) != MP_EXT) + return NULL; + int8_t type; + const char *const svp = *data; + + uint32_t len = mp_decode_extl(data, &type); + if (type != MP_UUID || uuid_unpack(data, len, uuid) == NULL) { + *data = svp; + return NULL; + } + return uuid; +} + +char * +mp_encode_uuid(char *data, const struct tt_uuid *uuid) +{ + return mp_encode_ext(data, MP_UUID, (char *)uuid, sizeof(*uuid)); +} diff --git a/src/lib/core/mp_uuid.h b/src/lib/core/mp_uuid.h new file mode 100644 index 000000000..fda0f3aed --- /dev/null +++ b/src/lib/core/mp_uuid.h @@ -0,0 +1,90 @@ +#ifndef TARANTOOL_LIB_CORE_MP_UUID_INCLUDED +#define TARANTOOL_LIB_CORE_MP_UUID_INCLUDED +/* + * Copyright 2020, Tarantool AUTHORS, please see AUTHORS file. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#if defined(__cplusplus) +extern "C" { +#endif /* defined(__cplusplus) */ + +struct tt_uuid; + +/** + * \brief Return the number of bytes an encoded uuid value takes. + */ +uint32_t +mp_sizeof_uuid(); + +/** + * Copy a uuid value from a buffer. Can be used in a combination + * with mp_decode_extl() instead of mp_decode_uuid() when multiple + * extension types are possible. + * + * \param data A buffer. + * \param len Length returned by mp_decode_extl, has to be equal + * to sizeof(struct tt_uuid), otherwise an error is + * returned. + * \param[out] uuid Uuid to be decoded. + * \return A pointer to the decoded uuid. + * NULL in case of an error. + * \post *data = *data + sizeof(struct tt_uuid). + */ +struct tt_uuid * +uuid_unpack(const char **data, uint32_t len, struct tt_uuid *uuid); + +/** + * \brief Decode a uuid from MsgPack \a data. + * \param data A buffer. + * \param[out] uuid Uuid to be decoded. + * \return A pointer to the decoded uuid. + * NULL in case of an error. + * \post *data = *data + mp_sizeof_uuid(). + */ +struct tt_uuid * +mp_decode_uuid(const char **data, struct tt_uuid *uuid); + +/** + * \brief Encode a uuid. + * \param data A buffer. + * \param uuid A uuid to encode. + * + * \return \a data + mp_sizeof_uuid() + */ +char * +mp_encode_uuid(char *data, const struct tt_uuid *uuid); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif /* defined(__cplusplus) */ + +#endif /* TARANTOOL_LIB_CORE_MP_UUID_INCLUDED */ diff --git a/src/lib/core/mpstream.c b/src/lib/core/mpstream.c index 2be1797d0..758bf5e55 100644 --- a/src/lib/core/mpstream.c +++ b/src/lib/core/mpstream.c @@ -34,6 +34,7 @@ #include #include "msgpuck.h" #include "mp_decimal.h" +#include "mp_uuid.h" void mpstream_reserve_slow(struct mpstream *stream, size_t size) @@ -197,6 +198,16 @@ mpstream_encode_decimal(struct mpstream *stream, const decimal_t *val) mpstream_advance(stream, pos - data); } +void +mpstream_encode_uuid(struct mpstream *stream, const struct tt_uuid *uuid) +{ + char *data = mpstream_reserve(stream, mp_sizeof_uuid()); + if (data == NULL) + return; + char *pos = mp_encode_uuid(data, uuid); + mpstream_advance(stream, pos - data); +} + void mpstream_memcpy(struct mpstream *stream, const void *src, uint32_t n) { diff --git a/src/lib/core/mpstream.h b/src/lib/core/mpstream.h index 3a022daa0..a60add143 100644 --- a/src/lib/core/mpstream.h +++ b/src/lib/core/mpstream.h @@ -38,6 +38,8 @@ extern "C" { #endif /* defined(__cplusplus) */ +struct tt_uuid; + /** * Ask the allocator to reserve at least size bytes. It can reserve * more, and update *size with the new size. @@ -140,6 +142,9 @@ mpstream_encode_binl(struct mpstream *stream, uint32_t len); void mpstream_encode_decimal(struct mpstream *stream, const decimal_t *val); +void +mpstream_encode_uuid(struct mpstream *stream, const struct tt_uuid *uuid); + /** Copies n bytes from memory area src to stream. */ void mpstream_memcpy(struct mpstream *stream, const void *src, uint32_t n); diff --git a/src/lib/msgpuck b/src/lib/msgpuck index 8ae606a16..0d273f95f 160000 --- a/src/lib/msgpuck +++ b/src/lib/msgpuck @@ -1 +1 @@ -Subproject commit 8ae606a1636dd89b2d61b154e5a1db03dce91657 +Subproject commit 0d273f95f8de64aeed698c354ca3bc7cb5ea461a diff --git a/src/lua/msgpack.c b/src/lua/msgpack.c index edbc15b72..fb49b1547 100644 --- a/src/lua/msgpack.c +++ b/src/lua/msgpack.c @@ -43,6 +43,7 @@ #include "lua/decimal.h" /* lua_pushdecimal() */ #include "lib/core/decimal.h" /* decimal_unpack() */ +#include "lib/core/mp_uuid.h" /* mp_decode_uuid() */ #include "lib/core/mp_extension_types.h" #include @@ -114,7 +115,7 @@ luamp_encode_r(struct lua_State *L, struct luaL_serializer *cfg, int top = lua_gettop(L); enum mp_type type; -restart: /* used by MP_EXT */ +restart: /* used by MP_EXT of unidentified subtype */ switch (field->type) { case MP_UINT: mpstream_encode_uint(stream, field->ival); @@ -190,7 +191,10 @@ restart: /* used by MP_EXT */ switch (field->ext_type) { case MP_DECIMAL: mpstream_encode_decimal(stream, field->decval); - return MP_EXT; + break; + case MP_UUID: + mpstream_encode_uuid(stream, field->uuidval); + break; default: /* Run trigger if type can't be encoded */ type = luamp_encode_extension(L, top, stream); @@ -310,10 +314,17 @@ luamp_decode(struct lua_State *L, struct luaL_serializer *cfg, { decimal_t *dec = lua_pushdecimal(L); dec = decimal_unpack(data, len, dec); - if (dec == NULL) { - lua_pop(L, -1); - luaL_error(L, "msgpack.decode: invalid MsgPack"); - } + if (dec == NULL) + goto ext_decode_err; + return; + } + case MP_UUID: + { + struct tt_uuid *uuid = luaL_pushuuid(L); + *data = svp; + uuid = mp_decode_uuid(data, uuid); + if (uuid == NULL) + goto ext_decode_err; return; } default: @@ -325,6 +336,10 @@ luamp_decode(struct lua_State *L, struct luaL_serializer *cfg, break; } } +return; +ext_decode_err: + lua_pop(L, -1); + luaL_error(L, "msgpack.decode: invalid MsgPack"); } diff --git a/src/lua/msgpackffi.lua b/src/lua/msgpackffi.lua index f775f2d41..f01ffaef0 100644 --- a/src/lua/msgpackffi.lua +++ b/src/lua/msgpackffi.lua @@ -20,6 +20,10 @@ char * mp_encode_decimal(char *data, decimal_t *dec); uint32_t mp_sizeof_decimal(const decimal_t *dec); +char * +mp_encode_uuid(char *data, const struct tt_uuid *uuid); +uint32_t +mp_sizeof_uuid(); float mp_decode_float(const char **data); double @@ -28,6 +32,8 @@ uint32_t mp_decode_extl(const char **data, int8_t *type); decimal_t * decimal_unpack(const char **data, uint32_t len, decimal_t *dec); +struct tt_uuid * +uuid_unpack(const char **data, uint32_t len, struct tt_uuid *uuid); ]]) local strict_alignment = (jit.arch == 'arm') @@ -129,6 +135,11 @@ local function encode_decimal(buf, num) builtin.mp_encode_decimal(p, num) end +local function encode_uuid(buf, uuid) + local p = buf:alloc(builtin.mp_sizeof_uuid()) + builtin.mp_encode_uuid(p, uuid) +end + local function encode_int(buf, num) if num >= 0 then if num <= 0x7f then @@ -311,6 +322,7 @@ on_encode(ffi.typeof('bool'), encode_bool_cdata) on_encode(ffi.typeof('float'), encode_float) on_encode(ffi.typeof('double'), encode_double) on_encode(ffi.typeof('decimal_t'), encode_decimal) +on_encode(ffi.typeof('struct tt_uuid'), encode_uuid) -------------------------------------------------------------------------------- -- Decoder @@ -495,6 +507,8 @@ local ext_decoder = { [0] = function(data, len) error("unsupported extension type") end, -- MP_DECIMAL [1] = function(data, len) local num = ffi.new("decimal_t") builtin.decimal_unpack(data, len, num) return num end, + -- MP_UUID + [2] = function(data, len) local uuid = ffi.new("struct tt_uuid") builtin.uuid_unpack(data, len, uuid) return uuid end, } local function decode_ext(data) diff --git a/src/lua/utils.c b/src/lua/utils.c index 54d18ac89..82f092cbf 100644 --- a/src/lua/utils.c +++ b/src/lua/utils.c @@ -45,9 +45,9 @@ static uint32_t CTID_STRUCT_IBUF; static uint32_t CTID_STRUCT_IBUF_PTR; static uint32_t CTID_CHAR_PTR; static uint32_t CTID_CONST_CHAR_PTR; +static uint32_t CTID_UUID; uint32_t CTID_DECIMAL; - void * luaL_pushcdata(struct lua_State *L, uint32_t ctypeid) { @@ -101,6 +101,12 @@ luaL_pushcdata(struct lua_State *L, uint32_t ctypeid) return cdataptr(cd); } +struct tt_uuid * +luaL_pushuuid(struct lua_State *L) +{ + return luaL_pushcdata(L, CTID_UUID); +} + void * luaL_checkcdata(struct lua_State *L, int idx, uint32_t *ctypeid) { @@ -746,6 +752,9 @@ luaL_tofield(struct lua_State *L, struct luaL_serializer *cfg, int index, if (cd->ctypeid == CTID_DECIMAL) { field->ext_type = MP_DECIMAL; field->decval = (decimal_t *) cdata; + } else if (cd->ctypeid == CTID_UUID) { + field->ext_type = MP_UUID; + field->uuidval = (struct tt_uuid *) cdata; } else { field->ext_type = MP_UNKNOWN_EXTENSION; } @@ -1286,5 +1295,15 @@ tarantool_lua_utils_init(struct lua_State *L) assert(CTID_CHAR_PTR != 0); CTID_CONST_CHAR_PTR = luaL_ctypeid(L, "const char *"); assert(CTID_CONST_CHAR_PTR != 0); + rc = luaL_cdef(L, "struct tt_uuid {" + "uint32_t time_low;" + "uint16_t time_mid;" + "uint16_t time_hi_and_version;" + "uint8_t clock_seq_hi_and_reserved;" + "uint8_t clock_seq_low;" + "uint8_t node[6];" + "};"); + CTID_UUID = luaL_ctypeid(L, "struct tt_uuid"); + assert(CTID_UUID != 0); return 0; } diff --git a/src/lua/utils.h b/src/lua/utils.h index 0b3672769..4bc041796 100644 --- a/src/lua/utils.h +++ b/src/lua/utils.h @@ -61,6 +61,7 @@ extern "C" { struct lua_State; struct ibuf; +struct tt_uuid; /** * Single global lua_State shared by core and modules. @@ -71,6 +72,9 @@ struct ibuf; extern struct lua_State *tarantool_L; extern struct ibuf *tarantool_lua_ibuf; +struct tt_uuid * +luaL_pushuuid(struct lua_State *L); + /** \cond public */ /** @@ -320,6 +324,7 @@ struct luaL_field { /* Array or map. */ uint32_t size; decimal_t *decval; + struct tt_uuid *uuidval; }; enum mp_type type; /* subtypes of MP_EXT */ diff --git a/src/lua/uuid.lua b/src/lua/uuid.lua index f8418cf4d..5d19a4408 100644 --- a/src/lua/uuid.lua +++ b/src/lua/uuid.lua @@ -5,15 +5,6 @@ local static_alloc = require('buffer').static_alloc local builtin = ffi.C ffi.cdef[[ -struct tt_uuid { - uint32_t time_low; - uint16_t time_mid; - uint16_t time_hi_and_version; - uint8_t clock_seq_hi_and_reserved; - uint8_t clock_seq_low; - uint8_t node[6]; -}; - void tt_uuid_create(struct tt_uuid *uu); int diff --git a/test/app-tap/lua/serializer_test.lua b/test/app-tap/lua/serializer_test.lua index 47edac621..2a668f898 100644 --- a/test/app-tap/lua/serializer_test.lua +++ b/test/app-tap/lua/serializer_test.lua @@ -204,6 +204,13 @@ local function test_decimal(test, s) rt(test, s, decimal.new('-1234567891234567890.0987654321987654321'), 'cdata') end +local function test_uuid(test, s) + local uuid = require('uuid') + test:plan(2) + + rt(test, s, uuid.new(), 'cdata') +end + local function test_boolean(test, s) test:plan(4) @@ -505,6 +512,7 @@ return { test_table = test_table; test_ucdata = test_ucdata; test_decimal = test_decimal; + test_uuid = test_uuid; test_depth = test_depth; test_decode_buffer = test_decode_buffer; } diff --git a/test/app-tap/msgpackffi.test.lua b/test/app-tap/msgpackffi.test.lua index 994402d15..0ee5f5edc 100755 --- a/test/app-tap/msgpackffi.test.lua +++ b/test/app-tap/msgpackffi.test.lua @@ -118,11 +118,12 @@ end tap.test("msgpackffi", function(test) local serializer = require('msgpackffi') - test:plan(11) + test:plan(12) test:test("unsigned", common.test_unsigned, serializer) test:test("signed", common.test_signed, serializer) test:test("double", common.test_double, serializer) test:test("decimal", common.test_decimal, serializer) + test:test("uuid", common.test_uuid, serializer) test:test("boolean", common.test_boolean, serializer) test:test("string", common.test_string, serializer) test:test("nil", common.test_nil, serializer) diff --git a/test/app/msgpack.result b/test/app/msgpack.result index 4b5aec784..ddf06fc9d 100644 --- a/test/app/msgpack.result +++ b/test/app/msgpack.result @@ -293,3 +293,24 @@ msgpack.decode(msgpack.encode(e)) == e --- - true ... +-- +-- gh-4268: msgpack encode/decode UUID +-- +uuid = require('uuid') +--- +... +fail = nil +--- +... +for i = 1,10 do\ + local a = uuid.new()\ + if msgpack.decode(msgpack.encode(a)) ~= a then\ + fail = a\ + end\ +end +--- +... +fail +--- +- null +... diff --git a/test/app/msgpack.test.lua b/test/app/msgpack.test.lua index 9224d870a..17e05df5c 100644 --- a/test/app/msgpack.test.lua +++ b/test/app/msgpack.test.lua @@ -99,3 +99,16 @@ msgpack.decode(msgpack.encode(b)) == b msgpack.decode(msgpack.encode(c)) == c msgpack.decode(msgpack.encode(d)) == d msgpack.decode(msgpack.encode(e)) == e + +-- +-- gh-4268: msgpack encode/decode UUID +-- +uuid = require('uuid') +fail = nil +for i = 1,10 do\ + local a = uuid.new()\ + if msgpack.decode(msgpack.encode(a)) ~= a then\ + fail = a\ + end\ +end +fail diff --git a/test/app/uuid.result b/test/app/uuid.result index 0713614c6..013c51282 100644 --- a/test/app/uuid.result +++ b/test/app/uuid.result @@ -106,7 +106,7 @@ uu.node[5] -- invalid values uuid.fromstr(nil) --- -- error: 'builtin/uuid.lua:47: fromstr(str)' +- error: 'builtin/uuid.lua:38: fromstr(str)' ... uuid.fromstr('') --- diff --git a/test/box/tuple.result b/test/box/tuple.result index a499aa43a..eb60a5645 100644 --- a/test/box/tuple.result +++ b/test/box/tuple.result @@ -1490,6 +1490,87 @@ box.tuple.is(box.tuple.new({1})) --- - true ... +-- +-- gh-4268 UUID in tuple +-- +uuid = require("uuid") +--- +... +-- Fixed randomly generated uuids to avoid problems with test +-- output comparison. +a = uuid.fromstr("c8f0fa1f-da29-438c-a040-393f1126ad39") +--- +... +b = uuid.fromstr("83eb4959-3de6-49fb-8890-6fb4423dd186") +--- +... +t = box.tuple.new(a, 2, b, "string") +--- +... +state, val = t:next() +--- +... +state +--- +- 1 +... +val == a +--- +- true +... +state, val = t:next(state) +--- +... +state +--- +- 2 +... +val +--- +- 2 +... +state, val = t:next(state) +--- +... +state +--- +- 3 +... +val == b +--- +- true +... +t:slice(1) +--- +- 2 +- 83eb4959-3de6-49fb-8890-6fb4423dd186 +- string +... +t:slice(-1) +--- +- string +... +t:slice(-2) +--- +- 83eb4959-3de6-49fb-8890-6fb4423dd186 +- string +... +msgpack.decode(msgpack.encode(t)) +--- +- [c8f0fa1f-da29-438c-a040-393f1126ad39, 2, 83eb4959-3de6-49fb-8890-6fb4423dd186, + 'string'] +- 46 +... +msgpackffi.decode(msgpackffi.encode(t)) +--- +- [c8f0fa1f-da29-438c-a040-393f1126ad39, 2, 83eb4959-3de6-49fb-8890-6fb4423dd186, + 'string'] +- 46 +... +t:bsize() +--- +- 45 +... msgpack.cfg({encode_max_depth = max_depth, encode_deep_as_nil = deep_as_nil}) --- ... diff --git a/test/box/tuple.test.lua b/test/box/tuple.test.lua index b83fca5cd..4201e9860 100644 --- a/test/box/tuple.test.lua +++ b/test/box/tuple.test.lua @@ -510,4 +510,29 @@ box.tuple.is('1') box.tuple.is(box.tuple.new()) box.tuple.is(box.tuple.new({1})) +-- +-- gh-4268 UUID in tuple +-- +uuid = require("uuid") +-- Fixed randomly generated uuids to avoid problems with test +-- output comparison. +a = uuid.fromstr("c8f0fa1f-da29-438c-a040-393f1126ad39") +b = uuid.fromstr("83eb4959-3de6-49fb-8890-6fb4423dd186") +t = box.tuple.new(a, 2, b, "string") +state, val = t:next() +state +val == a +state, val = t:next(state) +state +val +state, val = t:next(state) +state +val == b +t:slice(1) +t:slice(-1) +t:slice(-2) +msgpack.decode(msgpack.encode(t)) +msgpackffi.decode(msgpackffi.encode(t)) +t:bsize() + msgpack.cfg({encode_max_depth = max_depth, encode_deep_as_nil = deep_as_nil}) diff --git a/test/unit/uuid.c b/test/unit/uuid.c index c43d93b4f..4f6b963ba 100644 --- a/test/unit/uuid.c +++ b/test/unit/uuid.c @@ -1,5 +1,7 @@ #include "unit.h" #include "uuid/tt_uuid.h" +#include "core/mp_uuid.h" +#include "core/random.h" #include static void @@ -27,10 +29,28 @@ uuid_test(struct tt_uuid a, struct tt_uuid b, int expected_result) "%s %s %s", a_str, sign, b_str); } +static void +mp_uuid_test() +{ + plan(4); + char buf[18]; + char *data = buf; + const char *data1 = buf; + struct tt_uuid uu, ret; + random_init(); + tt_uuid_create(&uu); + char *end = mp_encode_uuid(data, &uu); + is(end - data, mp_sizeof_uuid(), "mp_sizeof_uuid() == encoded length"); + struct tt_uuid *rc = mp_decode_uuid(&data1, &ret); + is(rc, &ret, "mp_decode_uuid() return code"); + is(data1, end, "mp_sizeof_uuid() == decoded length"); + is(tt_uuid_compare(&uu, &ret), 0, "mp_decode_uuid(mp_encode_uuid(uu)) == uu"); +} + int main(void) { - plan(2); + plan(3); uuid_test( (struct tt_uuid){.time_low = 1712399963, @@ -63,5 +83,7 @@ main(void) .node = "v\025Oo9I"}, -1); + mp_uuid_test(); + return check_plan(); } diff --git a/test/unit/uuid.result b/test/unit/uuid.result index 40ccce759..50a1140c5 100644 --- a/test/unit/uuid.result +++ b/test/unit/uuid.result @@ -1,3 +1,9 @@ -1..2 +1..3 ok 1 - 6611265b-8852-4832-af8b-4164d52c62eb > 186ebbf7-cf97-4e2e-8b1b-76154f6f3949 ok 2 - 075b4148-8fb0-2e7f-af50-4164d52c62eb < 1fbc929f-5da8-28c5-8b36-76154f6f3949 + 1..4 + ok 1 - mp_sizeof_uuid() == encoded length + ok 2 - mp_decode_uuid() return code + ok 3 - mp_sizeof_uuid() == decoded length + ok 4 - mp_decode_uuid(mp_encode_uuid(uu)) == uu +ok 3 - subtests diff --git a/third_party/lua-cjson/lua_cjson.c b/third_party/lua-cjson/lua_cjson.c index 26e566a6f..6e1793a59 100644 --- a/third_party/lua-cjson/lua_cjson.c +++ b/third_party/lua-cjson/lua_cjson.c @@ -48,6 +48,9 @@ #include "strbuf.h" #include "lua/utils.h" +#include "lib/core/mp_extension_types.h" /* MP_DECIMAL, MP_UUID */ +#include "lib/core/tt_static.h" +#include "lib/uuid/tt_uuid.h" /* tt_uuid_to_string(), UUID_STR_LEN */ #define DEFAULT_ENCODE_KEEP_BUFFER 1 @@ -421,15 +424,21 @@ static void json_append_data(lua_State *l, struct luaL_serializer *cfg, json_append_array(l, cfg, current_depth + 1, json, field.size); return; case MP_EXT: - switch (field.ext_type) { - case MP_DECIMAL: - { - const char *str = decimal_to_string(field.decval); - return json_append_string(cfg, json, str, strlen(str)); - } - default: - assert(false); - } + switch (field.ext_type) { + case MP_DECIMAL: + { + const char *str = decimal_to_string(field.decval); + return json_append_string(cfg, json, str, strlen(str)); + } + case MP_UUID: + { + char *str = tt_static_buf(); + tt_uuid_to_string(field.uuidval, str); + return json_append_string(cfg, json, str, UUID_STR_LEN); + } + default: + assert(false); + } } } diff --git a/third_party/lua-yaml/lyaml.cc b/third_party/lua-yaml/lyaml.cc index af4f2f5d5..411c56f71 100644 --- a/third_party/lua-yaml/lyaml.cc +++ b/third_party/lua-yaml/lyaml.cc @@ -50,6 +50,9 @@ extern "C" { } /* extern "C" */ #include "lua/utils.h" #include "lib/core/decimal.h" +#include "lib/core/tt_static.h" +#include "lib/core/mp_extension_types.h" /* MP_DECIMAL, MP_UUID */ +#include "lib/uuid/tt_uuid.h" /* tt_uuid_to_string(), UUID_STR_LEN */ #define LUAYAML_TAG_PREFIX "tag:yaml.org,2002:" @@ -697,10 +700,18 @@ static int dump_node(struct lua_yaml_dumper *dumper) switch (field.ext_type) { case MP_DECIMAL: str = decimal_to_string(field.decval); - len = strlen(str); - break; + len = strlen(str); + break; + case MP_UUID: + { + char *buf = tt_static_buf(); + tt_uuid_to_string(field.uuidval, buf); + str = buf; + len = UUID_STR_LEN; + break; + } default: - assert(0); /* checked by luaL_checkfield() */ + assert(0); /* checked by luaL_checkfield() */ } break; } -- 2.21.1 (Apple Git-122.3)