in src/storage/scripting.cc [1209:1374]
std::string ReplyToRedisReply(redis::Connection *conn, lua_State *lua) {
std::string output;
const char *obj_s = nullptr;
size_t obj_len = 0;
int j = 0, mbulklen = 0;
int t = lua_type(lua, -1);
switch (t) {
case LUA_TSTRING:
obj_s = lua_tolstring(lua, -1, &obj_len);
output = redis::BulkString(std::string(obj_s, obj_len));
break;
case LUA_TBOOLEAN:
if (conn->GetProtocolVersion() == redis::RESP::v2) {
output = lua_toboolean(lua, -1) ? redis::Integer(1) : conn->NilString();
} else {
output = conn->Bool(lua_toboolean(lua, -1));
}
break;
case LUA_TNUMBER:
output = redis::Integer((int64_t)(lua_tonumber(lua, -1)));
break;
case LUA_TTABLE:
/* We need to check if it is an array, an error, or a status reply.
* Error are returned as a single element table with 'err' field.
* Status replies are returned as single element table with 'ok'
* field. */
/* Handle error reply. */
lua_pushstring(lua, "err");
lua_rawget(lua, -2);
t = lua_type(lua, -1);
if (t == LUA_TSTRING) {
output = redis::Error({Status::RedisErrorNoPrefix, lua_tostring(lua, -1)});
lua_pop(lua, 1);
return output;
}
lua_pop(lua, 1); /* Discard field name pushed before. */
/* Handle status reply. */
lua_pushstring(lua, "ok");
lua_rawget(lua, -2);
t = lua_type(lua, -1);
if (t == LUA_TSTRING) {
obj_s = lua_tolstring(lua, -1, &obj_len);
output = redis::BulkString(std::string(obj_s, obj_len));
lua_pop(lua, 1);
return output;
}
lua_pop(lua, 1); /* Discard the 'ok' field value we pushed */
/* Handle double reply. */
lua_pushstring(lua, "double");
lua_rawget(lua, -2);
t = lua_type(lua, -1);
if (t == LUA_TNUMBER) {
output = conn->Double(lua_tonumber(lua, -1));
lua_pop(lua, 1);
return output;
}
lua_pop(lua, 1); /* Discard the 'double' field value we pushed */
/* Handle big number reply. */
lua_pushstring(lua, "big_number");
lua_rawget(lua, -2);
t = lua_type(lua, -1);
if (t == LUA_TSTRING) {
obj_s = lua_tolstring(lua, -1, &obj_len);
output = conn->BigNumber(std::string(obj_s, obj_len));
lua_pop(lua, 1);
return output;
}
lua_pop(lua, 1); /* Discard the 'big_number' field value we pushed */
/* Handle verbatim reply. */
lua_pushstring(lua, "verbatim_string");
lua_rawget(lua, -2);
t = lua_type(lua, -1);
if (t == LUA_TTABLE) {
lua_pushstring(lua, "format");
lua_rawget(lua, -2);
t = lua_type(lua, -1);
if (t == LUA_TSTRING) {
const char *format = lua_tostring(lua, -1);
lua_pushstring(lua, "string");
lua_rawget(lua, -3);
t = lua_type(lua, -1);
if (t == LUA_TSTRING) {
obj_s = lua_tolstring(lua, -1, &obj_len);
output = conn->VerbatimString(std::string(format), std::string(obj_s, obj_len));
lua_pop(lua, 4);
return output;
}
// discard 'string'
lua_pop(lua, 1);
}
// discard 'format'
lua_pop(lua, 1);
}
lua_pop(lua, 1); /* Discard the 'verbatim_string' field value we pushed */
/* Handle map reply. */
lua_pushstring(lua, "map");
lua_rawget(lua, -2);
t = lua_type(lua, -1);
if (t == LUA_TTABLE) {
int map_len = 0;
std::string map_output;
lua_pushnil(lua);
while (lua_next(lua, -2)) {
lua_pushvalue(lua, -2);
// return key
map_output += ReplyToRedisReply(conn, lua);
lua_pop(lua, 1);
// return value
map_output += ReplyToRedisReply(conn, lua);
lua_pop(lua, 1);
map_len++;
}
output = conn->HeaderOfMap(map_len) + std::move(map_output);
lua_pop(lua, 1);
return output;
}
lua_pop(lua, 1); /* Discard the 'map' field value we pushed */
/* Handle set reply. */
lua_pushstring(lua, "set");
lua_rawget(lua, -2);
t = lua_type(lua, -1);
if (t == LUA_TTABLE) {
int set_len = 0;
std::string set_output;
lua_pushnil(lua);
while (lua_next(lua, -2)) {
lua_pop(lua, 1);
lua_pushvalue(lua, -1);
set_output += ReplyToRedisReply(conn, lua);
lua_pop(lua, 1);
set_len++;
}
output = conn->HeaderOfSet(set_len) + std::move(set_output);
lua_pop(lua, 1);
return output;
}
lua_pop(lua, 1); /* Discard the 'set' field value we pushed */
j = 1, mbulklen = 0;
while (true) {
lua_pushnumber(lua, j++);
lua_rawget(lua, -2);
t = lua_type(lua, -1);
if (t == LUA_TNIL) {
lua_pop(lua, 1);
break;
}
mbulklen++;
output += ReplyToRedisReply(conn, lua);
lua_pop(lua, 1);
}
output = redis::MultiLen(mbulklen) + output;
break;
default:
output = conn->NilString();
}
return output;
}