Internals: RESP Parser & Types¶
RedisType, RedisValue, RedisResult, RedisError¶
enum class RedisType
{
Null,
SimpleString,
Error,
Integer,
BulkString,
Array
};
struct RedisValue
{
using Array = std::vector<RedisValue>;
RedisType type{RedisType::Null};
std::variant<std::monostate, std::string, int64_t, Array> value;
bool is_null() const;
bool is_error() const;
bool is_simple_string() const;
bool is_bulk_string() const;
bool is_integer() const;
bool is_array() const;
const std::string& as_string() const;
int64_t as_integer() const;
const Array& as_array() const;
};
enum class RedisErrorCategory
{
Io,
Protocol,
ServerReply
};
struct RedisError
{
RedisErrorCategory category{RedisErrorCategory::Protocol};
std::string message;
};
template <typename T>
using RedisResult = std::expected<T, RedisError>;
- Io – socket errors, timeouts, short writes/reads, disconnects.
- Protocol – malformed RESP or unexpected reply type.
- ServerReply – Redis returned an error reply (
-ERR ...), propagated as failure.
RespParser¶
RespParser is an incremental RESP parser used by both RedisClient and RedisSubscriber.
class RespParser
{
public:
RespParser() = default;
void reset();
void feed(const uint8_t* data, std::size_t len);
std::optional<RedisValue> next();
private:
std::vector<uint8_t> buffer_;
std::size_t pos_{0};
bool ensure(std::size_t n) const;
std::optional<std::size_t> find_crlf(std::size_t from) const;
std::optional<std::string> read_line();
std::optional<RedisValue> parse_value();
std::optional<RedisValue> parse_simple_string();
std::optional<RedisValue> parse_error();
std::optional<RedisValue> parse_integer();
std::optional<RedisValue> parse_bulk_string();
std::optional<RedisValue> parse_array();
void compact_if_needed();
};
Usage pattern¶
RespParser parser;
// in the read loop:
parser.feed(reinterpret_cast<const uint8_t*>(buf.data()), buf.size());
while (true) {
auto val_opt = parser.next();
if (!val_opt) break;
RedisValue v = std::move(*val_opt);
// handle v
}
Parser behavior¶
feed()appends raw bytes to an internal buffer.-
next():- Returns
std::nulloptif there is not enough data for a full reply. - Otherwise parses exactly one RESP value and advances internal position.
compact_if_needed()periodically trims already-consumed data from the front of the buffer to avoid unbounded growth.
- Returns
Supported RESP prefixes:
'+'→ Simple string'-'→ Error string':'→ Integer'$'→ Bulk string (including null bulk when length< 0)'*'→ Array (recursive, elements can be any of the above)