[Tarantool-patches] [PATCH 3/4] box: add MsgPack encoding/decoding for UUID
Serge Petrenko
sergepetrenko at tarantool.org
Sat Apr 4 02:02:51 MSK 2020
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 <COPYRIGHT HOLDER> ``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
+ * <COPYRIGHT HOLDER> 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 <COPYRIGHT HOLDER> ``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
+ * <COPYRIGHT HOLDER> 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 <stdint.h>
+
+#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 <stdint.h>
#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 <fiber.h>
@@ -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 <string.h>
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)
More information about the Tarantool-patches
mailing list