Decouple parser from CommitRequest

This commit is contained in:
2025-08-17 13:36:53 -04:00
parent db2285dfda
commit fa2a2e4427
10 changed files with 636 additions and 460 deletions

View 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();
};