std::string ReplyToRedisReply()

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;
}