158 lines
5.3 KiB
C++
158 lines
5.3 KiB
C++
#pragma once
|
|
|
|
#include "commit_request_parser.hpp"
|
|
#include "json_token_enum.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;
|
|
const char *parse_error = nullptr;
|
|
bool parse_complete = false;
|
|
bool has_read_version_been_set = 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)) {
|
|
has_read_version_been_set = false;
|
|
}
|
|
|
|
void attach_arena(ArenaAllocator *arena) {
|
|
current_key = ArenaString{ArenaStlAllocator<char>(arena)};
|
|
current_string = ArenaString{ArenaStlAllocator<char>(arena)};
|
|
current_number = ArenaString{ArenaStlAllocator<char>(arena)};
|
|
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
|
|
ParseResult parse(CommitRequest &request, char *data, size_t len) override;
|
|
bool begin_streaming_parse(CommitRequest &request) override;
|
|
ParseStatus parse_chunk(char *data, size_t len) override;
|
|
ParseStatus finish_streaming_parse() override;
|
|
const char *get_parse_error() const override;
|
|
|
|
/**
|
|
* @brief Check if read version has been explicitly set during parsing.
|
|
*
|
|
* @note This function is primarily used for testing to verify parser
|
|
* behavior. It exposes internal parser state that is not typically needed in
|
|
* production code.
|
|
*
|
|
* @return true if read version was set during parsing
|
|
*/
|
|
bool has_read_version_been_set() const;
|
|
|
|
// 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();
|
|
};
|