Decouple parser from CommitRequest
This commit is contained in:
147
src/json_commit_request_parser.hpp
Normal file
147
src/json_commit_request_parser.hpp
Normal file
@@ -0,0 +1,147 @@
|
||||
#pragma once
|
||||
|
||||
#include "json_token_enum.hpp"
|
||||
#include "parser_interface.hpp"
|
||||
#include <memory>
|
||||
#include <simdutf.h>
|
||||
#include <weaseljson/weaseljson.h>
|
||||
|
||||
/**
|
||||
* @brief JSON-specific implementation of CommitRequestParser.
|
||||
*
|
||||
* This parser uses the weaseljson library to parse JSON-formatted
|
||||
* commit requests into CommitRequest objects.
|
||||
*/
|
||||
class JsonCommitRequestParser : public CommitRequestParser {
|
||||
public:
|
||||
// Parser state
|
||||
enum class ParseState {
|
||||
Root,
|
||||
PreconditionsArray,
|
||||
PreconditionObject,
|
||||
OperationsArray,
|
||||
OperationObject
|
||||
};
|
||||
|
||||
private:
|
||||
struct PreconditionParseState {
|
||||
Precondition::Type type;
|
||||
std::optional<uint64_t> version;
|
||||
// These are owned by CommitRequest::arena
|
||||
std::optional<std::string_view> key;
|
||||
std::optional<std::string_view> begin;
|
||||
std::optional<std::string_view> end;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Internal state for parsing an operation during JSON processing.
|
||||
*/
|
||||
struct OperationParseState {
|
||||
Operation::Type type;
|
||||
// These are owned by CommitRequest::arena
|
||||
std::optional<std::string_view> key;
|
||||
std::optional<std::string_view> value;
|
||||
std::optional<std::string_view> begin;
|
||||
std::optional<std::string_view> end;
|
||||
};
|
||||
|
||||
struct ParserContext {
|
||||
using ArenaString = std::basic_string<char, std::char_traits<char>,
|
||||
ArenaStlAllocator<char>>;
|
||||
|
||||
ParseState current_state = ParseState::Root;
|
||||
JsonTokenType current_key_token;
|
||||
// Only used if we need to accumulate the current key
|
||||
ArenaString current_key;
|
||||
ArenaString current_string;
|
||||
ArenaString current_number;
|
||||
bool in_key = false;
|
||||
const char *parse_error = nullptr;
|
||||
bool parse_complete = false;
|
||||
|
||||
// Current objects being parsed
|
||||
PreconditionParseState current_precondition{};
|
||||
OperationParseState current_operation{};
|
||||
|
||||
// Parsing state for nested structures
|
||||
ArenaString precondition_type;
|
||||
ArenaString operation_type;
|
||||
|
||||
// Constructor to initialize arena-allocated containers
|
||||
explicit ParserContext(ArenaAllocator *arena)
|
||||
: current_key(ArenaStlAllocator<char>(arena)),
|
||||
current_string(ArenaStlAllocator<char>(arena)),
|
||||
current_number(ArenaStlAllocator<char>(arena)),
|
||||
precondition_type(ArenaStlAllocator<char>(arena)),
|
||||
operation_type(ArenaStlAllocator<char>(arena)) {}
|
||||
|
||||
void reset_arena_memory(ArenaAllocator *arena) {
|
||||
current_key = ArenaString{ArenaStlAllocator<char>(arena)};
|
||||
current_string = ArenaString{ArenaStlAllocator<char>(arena)};
|
||||
current_number = ArenaString{ArenaStlAllocator<char>(arena)};
|
||||
in_key = false;
|
||||
current_precondition = {};
|
||||
current_operation = {};
|
||||
precondition_type = ArenaString{ArenaStlAllocator<char>(arena)};
|
||||
operation_type = ArenaString{ArenaStlAllocator<char>(arena)};
|
||||
current_state = ParseState::Root;
|
||||
}
|
||||
};
|
||||
|
||||
WeaselJsonParser *json_parser_ = nullptr;
|
||||
std::unique_ptr<ParserContext> parser_context_;
|
||||
CommitRequest *current_request_ = nullptr;
|
||||
static const WeaselJsonCallbacks json_callbacks;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new JsonCommitRequestParser.
|
||||
*/
|
||||
JsonCommitRequestParser();
|
||||
|
||||
/**
|
||||
* @brief Destructor - cleans up any active parser.
|
||||
*/
|
||||
~JsonCommitRequestParser();
|
||||
|
||||
// Non-copyable but movable
|
||||
JsonCommitRequestParser(const JsonCommitRequestParser &) = delete;
|
||||
JsonCommitRequestParser &operator=(const JsonCommitRequestParser &) = delete;
|
||||
JsonCommitRequestParser(JsonCommitRequestParser &&other) noexcept;
|
||||
JsonCommitRequestParser &operator=(JsonCommitRequestParser &&other) noexcept;
|
||||
|
||||
// CommitRequestParser interface implementation
|
||||
bool parse(CommitRequest &request, char *data, size_t len) override;
|
||||
bool begin_streaming_parse(CommitRequest &request) override;
|
||||
ParseStatus parse_chunk(CommitRequest &request, char *data,
|
||||
size_t len) override;
|
||||
ParseStatus finish_streaming_parse(CommitRequest &request) override;
|
||||
bool has_parse_error() const override;
|
||||
const char *get_parse_error() const override;
|
||||
|
||||
// Weaseljson callbacks (public for global callbacks)
|
||||
static void on_begin_object(void *userdata);
|
||||
static void on_end_object(void *userdata);
|
||||
static void on_string_data(void *userdata, const char *buf, int len,
|
||||
int done);
|
||||
static void on_key_data(void *userdata, const char *buf, int len, int done);
|
||||
static void on_begin_array(void *userdata);
|
||||
static void on_end_array(void *userdata);
|
||||
static void on_number_data(void *userdata, const char *buf, int len,
|
||||
int done);
|
||||
static void on_true_literal(void *userdata);
|
||||
static void on_false_literal(void *userdata);
|
||||
static void on_null_literal(void *userdata);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Decode a base64 string and store it in the arena.
|
||||
* @param base64_str The base64 encoded string
|
||||
* @return String view of decoded data, or empty view if decoding failed
|
||||
*/
|
||||
std::string_view decode_base64(std::string_view base64_str);
|
||||
|
||||
void handle_completed_string(std::string_view s);
|
||||
void handle_completed_number(std::string_view s);
|
||||
void on_complete();
|
||||
};
|
||||
Reference in New Issue
Block a user