diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ad2fef1de7d2500bf969d92caf76b905b4958b1e..ffd08aa786b01d173daf8575f45e8606efe2e65c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -94,6 +94,7 @@ set (common_sources
      lua/utils.c
      lua/errno.c
      lua/bsdsocket.cc
+     lua/pickle.cc
      ${lua_sources}
 )
 
diff --git a/src/box/lua/call.cc b/src/box/lua/call.cc
index 0428242fd3f294d1f9af81ebc824da7bedd63cf3..f0f6b38e9593d0b8814a30d740dbd516ce3e816f 100644
--- a/src/box/lua/call.cc
+++ b/src/box/lua/call.cc
@@ -29,8 +29,6 @@
 #include "box/lua/call.h"
 #include "pickle.h"
 
-#include <arpa/inet.h>
-
 #include "box/lua/tuple.h"
 #include "box/lua/index.h"
 #include "box/lua/space.h"
@@ -47,7 +45,6 @@
 #include "box/port.h"
 #include "box/request.h"
 #include "box/txn.h"
-#include "bit/bit.h"
 #include "box/access.h"
 #include "box/schema.h"
 
@@ -539,395 +536,6 @@ box_lua_call(struct request *request, struct txn *txn, struct port *port)
 	port_add_lua_multret(port, L);
 }
 
-/**
- * Convert box.pack() format specifier to Tarantool
- * binary protocol UPDATE opcode
- */
-static char format_to_opcode(char format)
-{
-	switch (format) {
-	case '=': return 0;
-	case '+': return 1;
-	case '&': return 2;
-	case '^': return 3;
-	case '|': return 4;
-	case ':': return 5;
-	case '#': return 6;
-	case '!': return 7;
-	case '-': return 8;
-	default: return format;
-	}
-}
-
-/**
- * Counterpart to @a format_to_opcode
- */
-static char opcode_to_format(char opcode)
-{
-	switch (opcode) {
-	case 0: return '=';
-	case 1: return '+';
-	case 2: return '&';
-	case 3: return '^';
-	case 4: return '|';
-	case 5: return ':';
-	case 6: return '#';
-	case 7: return '!';
-	case 8: return '-';
-	default: return opcode;
-	}
-}
-
-/**
- * To use Tarantool/Box binary protocol primitives from Lua, we
- * need a way to pack Lua variables into a binary representation.
- * We do it by exporting a helper function
- *
- * box.pack(format, args...)
- *
- * which takes the format, which is very similar to Perl 'pack'
- * format, and a list of arguments, and returns a binary string
- * which has the arguments packed according to the format.
- *
- * For example, a typical SELECT packet packs in Lua like this:
- *
- * pkt = box.pack("iiiiiip", -- pack format
- *                         0, -- space id
- *                         0, -- index id
- *                         0, -- offset
- *                         2^32, -- limit
- *                         1, -- number of SELECT arguments
- *                         1, -- tuple cardinality
- *                         key); -- the key to use for SELECT
- *
- * @sa doc/box-protocol.txt, binary protocol description
- * @todo: implement box.unpack(format, str), for testing purposes
- */
-static int
-lbox_pack(struct lua_State *L)
-{
-	const char *format = luaL_checkstring(L, 1);
-	/* first arg comes second */
-	int i = 2;
-	int nargs = lua_gettop(L);
-	size_t size;
-	const char *str;
-
-	RegionGuard region_guard(&fiber()->gc);
-	struct tbuf *b = tbuf_new(&fiber()->gc);
-
-	struct luaL_field field;
-	double dbl;
-	float flt;
-	char *data;
-	while (*format) {
-		if (i > nargs)
-			luaL_error(L, "box.pack: argument count does not match "
-				   "the format");
-		luaL_tofield(L, i, &field);
-		switch (*format) {
-		case 'B':
-		case 'b':
-			/* signed and unsigned 8-bit integers */
-			if (field.type != MP_UINT && field.type != MP_INT)
-				luaL_error(L, "box.pack: expected 8-bit int");
-
-			tbuf_append(b, (char *) &field.ival, sizeof(uint8_t));
-			break;
-		case 'S':
-		case 's':
-			/* signed and unsigned 16-bit integers */
-			if (field.type != MP_UINT && field.type != MP_INT)
-				luaL_error(L, "box.pack: expected 16-bit int");
-
-			tbuf_append(b, (char *) &field.ival, sizeof(uint16_t));
-			break;
-		case 'n':
-			/* signed and unsigned 16-bit big endian integers */
-			if (field.type != MP_UINT && field.type != MP_INT)
-				luaL_error(L, "box.pack: expected 16-bit int");
-
-			field.ival = (uint16_t) htons((uint16_t) field.ival);
-			tbuf_append(b, (char *) &field.ival, sizeof(uint16_t));
-			break;
-		case 'I':
-		case 'i':
-			/* signed and unsigned 32-bit integers */
-			if (field.type != MP_UINT && field.ival != MP_INT)
-				luaL_error(L, "box.pack: expected 32-bit int");
-
-			tbuf_append(b, (char *) &field.ival, sizeof(uint32_t));
-			break;
-		case 'N':
-			/* signed and unsigned 32-bit big endian integers */
-			if (field.type != MP_UINT && field.ival != MP_INT)
-				luaL_error(L, "box.pack: expected 32-bit int");
-
-			field.ival = htonl(field.ival);
-			tbuf_append(b, (char *) &field.ival, sizeof(uint32_t));
-			break;
-		case 'L':
-		case 'l':
-			/* signed and unsigned 64-bit integers */
-			if (field.type != MP_UINT && field.type != MP_INT)
-				luaL_error(L, "box.pack: expected 64-bit int");
-
-			tbuf_append(b, (char *) &field.ival, sizeof(uint64_t));
-			break;
-		case 'Q':
-		case 'q':
-			/* signed and unsigned 64-bit integers */
-			if (field.type != MP_UINT && field.type != MP_INT)
-				luaL_error(L, "box.pack: expected 64-bit int");
-
-			field.ival = bswap_u64(field.ival);
-			tbuf_append(b, (char *) &field.ival, sizeof(uint64_t));
-			break;
-		case 'd':
-			dbl = (double) lua_tonumber(L, i);
-			tbuf_append(b, (char *) &dbl, sizeof(double));
-			break;
-		case 'f':
-			flt = (float) lua_tonumber(L, i);
-			tbuf_append(b, (char *) &flt, sizeof(float));
-			break;
-		case 'A':
-		case 'a':
-			/* A sequence of bytes */
-			str = luaL_checklstring(L, i, &size);
-			tbuf_append(b, str, size);
-			break;
-		case 'P':
-		case 'p':
-			luamp_encode(L, b, i);
-			break;
-		case 'V':
-		{
-			int arg_count = luaL_checkint(L, i);
-			if (i + arg_count > nargs)
-				luaL_error(L, "box.pack: argument count does not match "
-					   "the format");
-			int first = i + 1;
-			int last = i + arg_count;
-			i += luamp_encodestack(L, b, first, last);
-			break;
-		}
-		case '=':
-			/* update tuple set foo = bar */
-		case '+':
-			/* set field += val */
-		case '-':
-			/* set field -= val */
-		case '&':
-			/* set field & =val */
-		case '|':
-			/* set field |= val */
-		case '^':
-			/* set field ^= val */
-		case ':':
-			/* splice */
-		case '#':
-			/* delete field */
-		case '!':
-			/* insert field */
-			/* field no */
-			tbuf_ensure(b, sizeof(uint32_t) + 1);
-			data = b->data + b->size;
-
-			data = pack_u32(data, lua_tointeger(L, i));
-			*data++ = format_to_opcode(*format);
-
-			assert(data <= b->data + b->capacity);
-			b->size = data - b->data;
-			break;
-		default:
-			luaL_error(L, "box.pack: unsupported pack "
-				   "format specifier '%c'", *format);
-		}
-		i++;
-		format++;
-	}
-
-	lua_pushlstring(L, tbuf_str(b), b->size);
-
-	return 1;
-}
-
-const char *
-box_unpack_response(struct lua_State *L, const char *s, const char *end)
-{
-	uint32_t tuple_count = pick_u32(&s, end);
-
-	/* Unpack and push tuples. */
-	while (tuple_count--) {
-		const char *t = s;
-		if (unlikely(mp_check(&s, end)))
-			tnt_raise(ClientError, ER_INVALID_MSGPACK);
-		if (unlikely(mp_typeof(*t) != MP_ARRAY))
-			tnt_raise(ClientError, ER_TUPLE_NOT_ARRAY);
-		struct tuple *tuple = tuple_new(tuple_format_ber, t, s);
-		lbox_pushtuple(L, tuple);
-	}
-	return s;
-}
-
-static int
-lbox_unpack(struct lua_State *L)
-{
-	size_t format_size = 0;
-	const char *format = luaL_checklstring(L, 1, &format_size);
-	const char *f = format;
-
-	size_t str_size = 0;
-	const char *str =  luaL_checklstring(L, 2, &str_size);
-	const char *end = str + str_size;
-	const char *s = str;
-
-	int save_stacksize = lua_gettop(L);
-
-	char charbuf;
-	uint8_t  u8buf;
-	uint16_t u16buf;
-	uint32_t u32buf;
-	double dbl;
-	float flt;
-
-#define CHECK_SIZE(cur) if (unlikely((cur) >= end)) {	                \
-	luaL_error(L, "box.unpack('%c'): got %d bytes (expected: %d+)",	\
-		   *f, (int) (end - str), (int) 1 + ((cur) - str));	\
-}
-	while (*f) {
-		switch (*f) {
-		case 'b':
-			CHECK_SIZE(s);
-			u8buf = *(uint8_t *) s;
-			lua_pushnumber(L, u8buf);
-			s++;
-			break;
-		case 's':
-			CHECK_SIZE(s + 1);
-			u16buf = *(uint16_t *) s;
-			lua_pushnumber(L, u16buf);
-			s += 2;
-			break;
-		case 'n':
-			CHECK_SIZE(s + 1);
-			u16buf = ntohs(*(uint16_t *) s);
-			lua_pushnumber(L, u16buf);
-			s += 2;
-			break;
-		case 'i':
-			CHECK_SIZE(s + 3);
-			u32buf = *(uint32_t *) s;
-			lua_pushnumber(L, u32buf);
-			s += 4;
-			break;
-		case 'N':
-			CHECK_SIZE(s + 3);
-			u32buf = ntohl(*(uint32_t *) s);
-			lua_pushnumber(L, u32buf);
-			s += 4;
-			break;
-		case 'l':
-			CHECK_SIZE(s + 7);
-			luaL_pushnumber64(L, *(uint64_t*) s);
-			s += 8;
-			break;
-		case 'q':
-			CHECK_SIZE(s + 7);
-			luaL_pushnumber64(L, bswap_u64(*(uint64_t*) s));
-			s += 8;
-			break;
-		case 'd':
-			CHECK_SIZE(s + 7);
-			dbl = *(double *) s;
-			lua_pushnumber(L, dbl);
-			s += 8;
-			break;
-		case 'f':
-			CHECK_SIZE(s + 3);
-			flt = *(float *) s;
-			lua_pushnumber(L, flt);
-			s += 4;
-			break;
-		case 'a':
-		case 'A': /* The rest of the data is a Lua string. */
-			lua_pushlstring(L, s, end - s);
-			s = end;
-			break;
-		case 'P':
-		case 'p':
-		{
-			const char *data = s;
-			if (unlikely(mp_check(&s, end)))
-				tnt_raise(ClientError, ER_INVALID_MSGPACK);
-			luamp_decode(L, &data);
-			assert(data == s);
-			break;
-		}
-		case '=':
-			/* update tuple set foo = bar */
-		case '+':
-			/* set field += val */
-		case '-':
-			/* set field -= val */
-		case '&':
-			/* set field & =val */
-		case '|':
-			/* set field |= val */
-		case '^':
-			/* set field ^= val */
-		case ':':
-			/* splice */
-		case '#':
-			/* delete field */
-		case '!':
-			/* insert field */
-			CHECK_SIZE(s + 4);
-
-			/* field no */
-			u32buf = *(uint32_t *) s;
-
-			/* opcode */
-			charbuf = *(s + 4);
-			charbuf = opcode_to_format(charbuf);
-			if (charbuf != *f) {
-				luaL_error(L, "box.unpack('%s'): "
-					   "unexpected opcode: "
-					   "offset %d, expected '%c',"
-					   "found '%c'",
-					   format, s - str, *f, charbuf);
-			}
-
-			lua_pushnumber(L, u32buf);
-			s += 5;
-			break;
-
-		case 'R': /* Unpack server response, IPROTO format. */
-		{
-			s = box_unpack_response(L, s, end);
-			break;
-		}
-		default:
-			luaL_error(L, "box.unpack: unsupported "
-				   "format specifier '%c'", *f);
-		}
-		f++;
-	}
-
-	assert(s <= end);
-
-	if (s != end) {
-		luaL_error(L, "box.unpack('%s'): too many bytes: "
-			   "unpacked %d, total %d",
-			   format, s - str, str_size);
-	}
-
-	return lua_gettop(L) - save_stacksize;
-
-#undef CHECK_SIZE
-}
-
 static int
 lbox_snapshot(struct lua_State *L)
 {
@@ -943,8 +551,6 @@ lbox_snapshot(struct lua_State *L)
 
 static const struct luaL_reg boxlib[] = {
 	{"raise", lbox_raise},
-	{"pack", lbox_pack},
-	{"unpack", lbox_unpack},
 	{"snapshot", lbox_snapshot},
 	{NULL, NULL}
 };
diff --git a/src/lua/init.cc b/src/lua/init.cc
index 60e1fe30ae71103d0a85c9b90d41e7882d635eca..fbc084083065a976f7dd6e01ca59bf6c01bb7d15 100644
--- a/src/lua/init.cc
+++ b/src/lua/init.cc
@@ -56,6 +56,7 @@ extern "C" {
 #include "lua/cjson.h"
 #include "lua/yaml.h"
 #include "lua/msgpack.h"
+#include "lua/pickle.h"
 
 #include <ctype.h>
 #include "small/region.h"
@@ -236,6 +237,7 @@ tarantool_lua_init(const char *tarantool_bin, int argc, char **argv)
 	tarantool_lua_bsdsocket_init(L);
 	tarantool_lua_session_init(L);
 	tarantool_lua_error_init(L);
+	tarantool_lua_pickle_init(L);
 	luaopen_msgpack(L);
 	lua_pop(L, 1);
 
diff --git a/src/lua/pickle.cc b/src/lua/pickle.cc
new file mode 100644
index 0000000000000000000000000000000000000000..09fafad3cd323be1a85c991fc25ad5c362503728
--- /dev/null
+++ b/src/lua/pickle.cc
@@ -0,0 +1,266 @@
+/*
+ * 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 "lua/pickle.h"
+
+#include <arpa/inet.h>
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+} /* extern "C" */
+
+#include "lua/utils.h"
+#include <tbuf.h>
+#include <fiber.h>
+#include "bit/bit.h"
+
+static int
+lbox_pack(struct lua_State *L)
+{
+	const char *format = luaL_checkstring(L, 1);
+	/* first arg comes second */
+	int i = 2;
+	int nargs = lua_gettop(L);
+	size_t size;
+	const char *str;
+
+	RegionGuard region_guard(&fiber()->gc);
+	struct tbuf *b = tbuf_new(&fiber()->gc);
+
+	struct luaL_field field;
+	double dbl;
+	float flt;
+	while (*format) {
+		if (i > nargs)
+			luaL_error(L, "pickle.pack: argument count does not match "
+				   "the format");
+		luaL_tofield(L, i, &field);
+		switch (*format) {
+		case 'B':
+		case 'b':
+			/* signed and unsigned 8-bit integers */
+			if (field.type != MP_UINT && field.type != MP_INT)
+				luaL_error(L, "pickle.pack: expected 8-bit int");
+
+			tbuf_append(b, (char *) &field.ival, sizeof(uint8_t));
+			break;
+		case 'S':
+		case 's':
+			/* signed and unsigned 16-bit integers */
+			if (field.type != MP_UINT && field.type != MP_INT)
+				luaL_error(L, "pickle.pack: expected 16-bit int");
+
+			tbuf_append(b, (char *) &field.ival, sizeof(uint16_t));
+			break;
+		case 'n':
+			/* signed and unsigned 16-bit big endian integers */
+			if (field.type != MP_UINT && field.type != MP_INT)
+				luaL_error(L, "pickle.pack: expected 16-bit int");
+
+			field.ival = (uint16_t) htons((uint16_t) field.ival);
+			tbuf_append(b, (char *) &field.ival, sizeof(uint16_t));
+			break;
+		case 'I':
+		case 'i':
+			/* signed and unsigned 32-bit integers */
+			if (field.type != MP_UINT && field.ival != MP_INT)
+				luaL_error(L, "pickle.pack: expected 32-bit int");
+
+			tbuf_append(b, (char *) &field.ival, sizeof(uint32_t));
+			break;
+		case 'N':
+			/* signed and unsigned 32-bit big endian integers */
+			if (field.type != MP_UINT && field.ival != MP_INT)
+				luaL_error(L, "pickle.pack: expected 32-bit int");
+
+			field.ival = htonl(field.ival);
+			tbuf_append(b, (char *) &field.ival, sizeof(uint32_t));
+			break;
+		case 'L':
+		case 'l':
+			/* signed and unsigned 64-bit integers */
+			if (field.type != MP_UINT && field.type != MP_INT)
+				luaL_error(L, "pickle.pack: expected 64-bit int");
+
+			tbuf_append(b, (char *) &field.ival, sizeof(uint64_t));
+			break;
+		case 'Q':
+		case 'q':
+			/* signed and unsigned 64-bit integers */
+			if (field.type != MP_UINT && field.type != MP_INT)
+				luaL_error(L, "pickle.pack: expected 64-bit int");
+
+			field.ival = bswap_u64(field.ival);
+			tbuf_append(b, (char *) &field.ival, sizeof(uint64_t));
+			break;
+		case 'd':
+			dbl = (double) lua_tonumber(L, i);
+			tbuf_append(b, (char *) &dbl, sizeof(double));
+			break;
+		case 'f':
+			flt = (float) lua_tonumber(L, i);
+			tbuf_append(b, (char *) &flt, sizeof(float));
+			break;
+		case 'A':
+		case 'a':
+			/* A sequence of bytes */
+			str = luaL_checklstring(L, i, &size);
+			tbuf_append(b, str, size);
+			break;
+		default:
+			luaL_error(L, "pickle.pack: unsupported pack "
+				   "format specifier '%c'", *format);
+		}
+		i++;
+		format++;
+	}
+
+	lua_pushlstring(L, tbuf_str(b), b->size);
+
+	return 1;
+}
+
+
+static int
+lbox_unpack(struct lua_State *L)
+{
+	size_t format_size = 0;
+	const char *format = luaL_checklstring(L, 1, &format_size);
+	const char *f = format;
+
+	size_t str_size = 0;
+	const char *str =  luaL_checklstring(L, 2, &str_size);
+	const char *end = str + str_size;
+	const char *s = str;
+
+	int save_stacksize = lua_gettop(L);
+
+	uint8_t  u8buf;
+	uint16_t u16buf;
+	uint32_t u32buf;
+	double dbl;
+	float flt;
+
+#define CHECK_SIZE(cur) if (unlikely((cur) >= end)) {	                \
+	luaL_error(L, "pickle.unpack('%c'): got %d bytes (expected: %d+)",	\
+		   *f, (int) (end - str), (int) 1 + ((cur) - str));	\
+}
+	while (*f) {
+		switch (*f) {
+		case 'b':
+			CHECK_SIZE(s);
+			u8buf = *(uint8_t *) s;
+			lua_pushnumber(L, u8buf);
+			s++;
+			break;
+		case 's':
+			CHECK_SIZE(s + 1);
+			u16buf = *(uint16_t *) s;
+			lua_pushnumber(L, u16buf);
+			s += 2;
+			break;
+		case 'n':
+			CHECK_SIZE(s + 1);
+			u16buf = ntohs(*(uint16_t *) s);
+			lua_pushnumber(L, u16buf);
+			s += 2;
+			break;
+		case 'i':
+			CHECK_SIZE(s + 3);
+			u32buf = *(uint32_t *) s;
+			lua_pushnumber(L, u32buf);
+			s += 4;
+			break;
+		case 'N':
+			CHECK_SIZE(s + 3);
+			u32buf = ntohl(*(uint32_t *) s);
+			lua_pushnumber(L, u32buf);
+			s += 4;
+			break;
+		case 'l':
+			CHECK_SIZE(s + 7);
+			luaL_pushnumber64(L, *(uint64_t*) s);
+			s += 8;
+			break;
+		case 'q':
+			CHECK_SIZE(s + 7);
+			luaL_pushnumber64(L, bswap_u64(*(uint64_t*) s));
+			s += 8;
+			break;
+		case 'd':
+			CHECK_SIZE(s + 7);
+			dbl = *(double *) s;
+			lua_pushnumber(L, dbl);
+			s += 8;
+			break;
+		case 'f':
+			CHECK_SIZE(s + 3);
+			flt = *(float *) s;
+			lua_pushnumber(L, flt);
+			s += 4;
+			break;
+		case 'a':
+		case 'A': /* The rest of the data is a Lua string. */
+			lua_pushlstring(L, s, end - s);
+			s = end;
+			break;
+		default:
+			luaL_error(L, "pickle.unpack: unsupported "
+				   "format specifier '%c'", *f);
+		}
+		f++;
+	}
+
+	assert(s <= end);
+
+	if (s != end) {
+		luaL_error(L, "pickle.unpack('%s'): too many bytes: "
+			   "unpacked %d, total %d",
+			   format, s - str, str_size);
+	}
+
+	return lua_gettop(L) - save_stacksize;
+
+#undef CHECK_SIZE
+}
+
+void
+tarantool_lua_pickle_init(struct lua_State *L)
+{
+	const luaL_reg picklelib[] = {
+		{"pack", lbox_pack},
+		{"unpack", lbox_unpack},
+		{ NULL, NULL}
+	};
+
+	luaL_register_module(L, "pickle", picklelib);
+	lua_pop(L, 1);
+}
diff --git a/src/lua/pickle.h b/src/lua/pickle.h
new file mode 100644
index 0000000000000000000000000000000000000000..ead5695a790a77e5153c29ef8906f41aee4105ce
--- /dev/null
+++ b/src/lua/pickle.h
@@ -0,0 +1,35 @@
+#ifndef TARANTOOL_LUA_PICKLE_H_INCLUDED
+#define TARANTOOL_LUA_PICKLE_H_INCLUDED
+/*
+ * 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.
+ */
+
+void
+tarantool_lua_pickle_init(struct lua_State *L);
+
+#endif /* TARANTOOL_LUA_PICKLE_H_INCLUDED */
diff --git a/test/box/bsdsocket.result b/test/box/bsdsocket.result
index 111e22bc3692a980f357031ae20ae4e5fb201978..164901710624c75492ed52fef92c04610beca78a 100644
--- a/test/box/bsdsocket.result
+++ b/test/box/bsdsocket.result
@@ -1,6 +1,9 @@
 json = require('json')
 ---
 ...
+pickle = require('pickle')
+---
+...
 socket = require('socket')
 ---
 ...
@@ -91,7 +94,7 @@ s:wait(.01)
 ---
 - RW
 ...
-s:syswrite(box.pack('iii', 65280, 0, 12334))
+s:syswrite(pickle.pack('iii', 65280, 0, 12334))
 ---
 - 12
 ...
@@ -103,11 +106,11 @@ s:wait(.01)
 ---
 - RW
 ...
-box.unpack('iii', s:sysread(4096))
+pickle.unpack('iii', s:sysread(4096))
 ---
-- error: 'box.unpack(''iii''): too many bytes: unpacked 12, total 128'
+- error: 'pickle.unpack(''iii''): too many bytes: unpacked 12, total 128'
 ...
-s:syswrite(box.pack('iii', 65280, 0, 12335))
+s:syswrite(pickle.pack('iii', 65280, 0, 12335))
 ---
 - 12
 ...
diff --git a/test/box/bsdsocket.test.lua b/test/box/bsdsocket.test.lua
index 95af2305217585fadc2f54d7fb5083404b5f2753..25eab88e90b74ee8de5229c4fd976760f477be07 100644
--- a/test/box/bsdsocket.test.lua
+++ b/test/box/bsdsocket.test.lua
@@ -1,4 +1,5 @@
 json = require('json')
+pickle = require('pickle')
 socket = require('socket')
 type(socket)
 
@@ -27,12 +28,12 @@ s:writable(.00000000000001)
 s:writable(0)
 s:wait(.01)
 
-s:syswrite(box.pack('iii', 65280, 0, 12334))
+s:syswrite(pickle.pack('iii', 65280, 0, 12334))
 s:readable(1)
 s:wait(.01)
-box.unpack('iii', s:sysread(4096))
+pickle.unpack('iii', s:sysread(4096))
 
-s:syswrite(box.pack('iii', 65280, 0, 12335))
+s:syswrite(pickle.pack('iii', 65280, 0, 12335))
 s:readable(1)
 string.len(s:sysread(4096))
 s:close()
diff --git a/test/box/misc.result b/test/box/misc.result
index b6e031a74281772f9dace5fa5c7324534b7d6a3c..d0cc405924b2dc41527dc09c6e8d15144635c22f 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -21,7 +21,6 @@ t
   - index
   - info
   - net
-  - pack
   - raise
   - schema
   - slab
@@ -29,7 +28,6 @@ t
   - space
   - stat
   - tuple
-  - unpack
 ...
 t = nil
 ---
@@ -318,7 +316,7 @@ tonumber64('184467440737095516155')
 ---
 - error: 'lua_tointeger64: bad argument'
 ...
-string.byte(box.pack('p', tonumber64(123)))
+string.byte(require('msgpack').encode(tonumber64(123)))
 ---
 - 123
 ...
diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua
index 8b7ff88588fa88d2edda430ab482c8fb1c7cb77e..024806cf08558490ba063068bcd3bf2b709dd7f8 100644
--- a/test/box/misc.test.lua
+++ b/test/box/misc.test.lua
@@ -103,7 +103,7 @@ tonumber64('18446744073709551615') == tonumber64('18446744073709551615')
 tonumber64('18446744073709551615') + 1
 tonumber64(-1)
 tonumber64('184467440737095516155')
-string.byte(box.pack('p', tonumber64(123)))
+string.byte(require('msgpack').encode(tonumber64(123)))
 --  A test case for Bug#1061747 'tonumber64 is not transitive'
 tonumber64(tonumber64(2))
 tostring(tonumber64(tonumber64(3)))
diff --git a/test/box/pack.result b/test/box/pack.result
index b83e831380c840c7e1fcd0b378d7916ce317d1fe..8c1333abbbcebb8bb30ddfb4d78572faa18bd343 100644
--- a/test/box/pack.result
+++ b/test/box/pack.result
@@ -1,111 +1,78 @@
--- Test box.pack()
-box.pack()
+-- Test pickle.pack()
+pickle = require('pickle')
+---
+...
+pickle.pack()
 ---
 - error: 'bad argument #1 to ''?'' (string expected, got no value)'
 ...
-box.pack(1)
+pickle.pack(1)
 ---
-- error: 'box.pack: argument count does not match the format'
+- error: 'pickle.pack: argument count does not match the format'
 ...
-box.pack('abc')
+pickle.pack('abc')
 ---
-- error: 'box.pack: argument count does not match the format'
+- error: 'pickle.pack: argument count does not match the format'
 ...
-box.pack('a', ' - hello')
+pickle.pack('a', ' - hello')
 ---
 - ' - hello'
 ...
-box.pack('Aa', ' - hello', ' world')
+pickle.pack('Aa', ' - hello', ' world')
 ---
 - ' - hello world'
 ...
-string.sub(box.pack('p', 1684234849), 2)
----
-- dcba
-...
-box.pack('p', 'this string is 45 characters long 1234567890 ')
----
-- !!binary 2S10aGlzIHN0cmluZyBpcyA0NSBjaGFyYWN0ZXJzIGxvbmcgMTIzNDU2Nzg5MCA=
-...
-box.pack('s', 0x4d)
+pickle.pack('s', 0x4d)
 ---
 - "M\0"
 ...
-box.pack('ssss', 25940, 29811, 28448, 11883)
+pickle.pack('ssss', 25940, 29811, 28448, 11883)
 ---
 - Test ok.
 ...
-box.pack('SSSS', 25940, 29811, 28448, 11883)
+pickle.pack('SSSS', 25940, 29811, 28448, 11883)
 ---
 - Test ok.
 ...
-box.pack('SSSSSSSS', 28493, 29550, 27680, 27497, 29541, 20512, 29285, 8556)
+pickle.pack('SSSSSSSS', 28493, 29550, 27680, 27497, 29541, 20512, 29285, 8556)
 ---
 - Mons likes Perl!
 ...
-box.pack('bsil', 84, 29541, 1802444916, 2338318684567380014ULL)
+pickle.pack('bsil', 84, 29541, 1802444916, 2338318684567380014ULL)
 ---
 - 'Test ok. Let`s '
 ...
-box.unpack('b', 'T')
+pickle.unpack('b', 'T')
 ---
 - 84
 ...
-box.unpack('s', 'Te')
+pickle.unpack('s', 'Te')
 ---
 - 25940
 ...
-box.unpack('i', 'Test')
+pickle.unpack('i', 'Test')
 ---
 - 1953719636
 ...
-box.unpack('l', 'Test ok.')
+pickle.unpack('l', 'Test ok.')
 ---
 - 3344889333436081492
 ...
-box.unpack('bsil', box.pack('bsil', 255, 65535, 4294967295, tonumber64('18446744073709551615')))
+pickle.unpack('bsil', pickle.pack('bsil', 255, 65535, 4294967295, tonumber64('18446744073709551615')))
 ---
 - 255
 - 65535
 - 4294967295
 - 18446744073709551615
 ...
-box.unpack('ppp', box.pack('ppp', 'one', 'two', 'three'))
----
-- one
-- two
-- three
-...
-num, str, num64 = box.unpack('ppp', box.pack('ppp', 666, 'string', tonumber64('666666666666666')))
----
-...
-num, str, num64
----
-- 666
-- string
-- 666666666666666
-...
-box.unpack('=p', box.pack('=p', 1, '666'))
----
-- 1
-- '666'
-...
-box.unpack('','')
----
-...
-box.unpack('ii', box.pack('i', 1))
----
-- error: 'box.unpack(''i''): got 4 bytes (expected: 8+)'
-...
-box.unpack('i', box.pack('ii', 1, 1))
+pickle.unpack('','')
 ---
-- error: 'box.unpack(''i''): too many bytes: unpacked 4, total 8'
 ...
-box.unpack('+p', box.pack('=p', 1, '666'))
+pickle.unpack('ii', pickle.pack('i', 1))
 ---
-- error: 'box.unpack(''+p''): unexpected opcode: offset 0, expected ''+'',found ''='''
+- error: 'pickle.unpack(''i''): got 4 bytes (expected: 8+)'
 ...
-box.unpack('p', box.pack('p', 'this this this this'))
+pickle.unpack('i', pickle.pack('ii', 1, 1))
 ---
-- this this this this
+- error: 'pickle.unpack(''i''): too many bytes: unpacked 4, total 8'
 ...
diff --git a/test/box/pack.test.lua b/test/box/pack.test.lua
index 2dff411eede6ca5e94a0476d84e180cf144a7e75..8f7a6a0f45cf89c5e556a95a1306e28eb859ee7d 100644
--- a/test/box/pack.test.lua
+++ b/test/box/pack.test.lua
@@ -1,27 +1,21 @@
--- Test box.pack()
-box.pack()
-box.pack(1)
-box.pack('abc')
-box.pack('a', ' - hello')
-box.pack('Aa', ' - hello', ' world')
-string.sub(box.pack('p', 1684234849), 2)
-box.pack('p', 'this string is 45 characters long 1234567890 ')
-box.pack('s', 0x4d)
-box.pack('ssss', 25940, 29811, 28448, 11883)
-box.pack('SSSS', 25940, 29811, 28448, 11883)
-box.pack('SSSSSSSS', 28493, 29550, 27680, 27497, 29541, 20512, 29285, 8556)
-box.pack('bsil', 84, 29541, 1802444916, 2338318684567380014ULL)
-box.unpack('b', 'T')
-box.unpack('s', 'Te')
-box.unpack('i', 'Test')
-box.unpack('l', 'Test ok.')
-box.unpack('bsil', box.pack('bsil', 255, 65535, 4294967295, tonumber64('18446744073709551615')))
-box.unpack('ppp', box.pack('ppp', 'one', 'two', 'three'))
-num, str, num64 = box.unpack('ppp', box.pack('ppp', 666, 'string', tonumber64('666666666666666')))
-num, str, num64
-box.unpack('=p', box.pack('=p', 1, '666'))
-box.unpack('','')
-box.unpack('ii', box.pack('i', 1))
-box.unpack('i', box.pack('ii', 1, 1))
-box.unpack('+p', box.pack('=p', 1, '666'))
-box.unpack('p', box.pack('p', 'this this this this'))
+-- Test pickle.pack()
+pickle = require('pickle')
+
+pickle.pack()
+pickle.pack(1)
+pickle.pack('abc')
+pickle.pack('a', ' - hello')
+pickle.pack('Aa', ' - hello', ' world')
+pickle.pack('s', 0x4d)
+pickle.pack('ssss', 25940, 29811, 28448, 11883)
+pickle.pack('SSSS', 25940, 29811, 28448, 11883)
+pickle.pack('SSSSSSSS', 28493, 29550, 27680, 27497, 29541, 20512, 29285, 8556)
+pickle.pack('bsil', 84, 29541, 1802444916, 2338318684567380014ULL)
+pickle.unpack('b', 'T')
+pickle.unpack('s', 'Te')
+pickle.unpack('i', 'Test')
+pickle.unpack('l', 'Test ok.')
+pickle.unpack('bsil', pickle.pack('bsil', 255, 65535, 4294967295, tonumber64('18446744073709551615')))
+pickle.unpack('','')
+pickle.unpack('ii', pickle.pack('i', 1))
+pickle.unpack('i', pickle.pack('ii', 1, 1))