// Copyright 2021, Roman Gershman. All rights reserved. // See LICENSE for licensing terms. // #pragma once #include #include "core/resp_expr.h" namespace dfly { /** * @brief Zero-copy (best-effort) parser. * */ class RedisParser { public: enum Result { OK, INPUT_PENDING, BAD_ARRAYLEN, BAD_BULKLEN, BAD_STRING, BAD_INT }; using Buffer = RespExpr::Buffer; explicit RedisParser(bool server_mode = true) : server_mode_(server_mode) { } /** * @brief Parses str into res. "consumed" stores number of bytes consumed from str. * * A caller should not invalidate str if the parser returns RESP_OK as long as he continues * accessing res. However, if parser returns MORE_INPUT a caller may discard consumed * part of str because parser caches the intermediate state internally according to 'consumed' * result. * * Note: A parser does not always guarantee progress, i.e. if a small buffer was passed it may * returns MORE_INPUT with consumed == 0. * */ Result Parse(Buffer str, uint32_t* consumed, RespVec* res); void SetClientMode() { server_mode_ = false; } size_t parselen_hint() const { return bulk_len_; } size_t stash_size() const { return stash_.size(); } const std::vector>& stash() const { return stash_;} private: void InitStart(uint8_t prefix_b, RespVec* res); void StashState(RespVec* res); // Skips the first character (*). Result ConsumeArrayLen(Buffer str); Result ParseArg(Buffer str); Result ConsumeBulk(Buffer str); Result ParseInline(Buffer str); // Updates last_consumed_ Result ParseNum(Buffer str, int64_t* res); void HandleFinishArg(); void ExtendLastString(Buffer str); enum State : uint8_t { INIT_S = 0, INLINE_S, ARRAY_LEN_S, PARSE_ARG_S, // Parse [$:+-]string\r\n BULK_STR_S, FINISH_ARG_S, CMD_COMPLETE_S, }; State state_ = INIT_S; Result last_result_ = OK; uint32_t last_consumed_ = 0; uint32_t bulk_len_ = 0; uint32_t last_stashed_level_ = 0, last_stashed_index_ = 0; // expected expression length, pointer to expression vector. absl::InlinedVector, 4> parse_stack_; std::vector> stash_; using BlobPtr = std::unique_ptr; std::vector buf_stash_; RespVec* cached_expr_ = nullptr; bool is_broken_token_ = false; bool server_mode_ = true; }; } // namespace dfly