From ec7f1183d8c0c2893603bd4e8bacb038570e1958 Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Sun, 2 Oct 2022 21:24:12 +0300 Subject: [PATCH] Basic hooking into json parsing. Also allow customization of the fallback meta-method. --- module/Library/JSON.cpp | 47 +++++++++++++++++++++++++++++++++++++- module/Library/JSON.hpp | 50 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 94 insertions(+), 3 deletions(-) diff --git a/module/Library/JSON.cpp b/module/Library/JSON.cpp index bdefaef5..aaeedfea 100644 --- a/module/Library/JSON.cpp +++ b/module/Library/JSON.cpp @@ -2,6 +2,7 @@ #include "Library/JSON.hpp" // ------------------------------------------------------------------------------------------------ +#include #include // ------------------------------------------------------------------------------------------------ @@ -180,6 +181,23 @@ CtxJSON & CtxJSON::CloseArray() return *this; } +// ------------------------------------------------------------------------------------------------ +CtxJSON & CtxJSON::ReopenArray() +{ + // If the last character is a comma then remove it + if (mOutput.back() == ',') + { + mOutput.pop_back(); + } + // If the last character is the array-end character then replace it with a comma + if (mOutput.back() == ']') + { + mOutput.back() = ','; + } + // Allow chaining + return *this; +} + // ------------------------------------------------------------------------------------------------ CtxJSON & CtxJSON::OpenObject() { @@ -212,6 +230,23 @@ CtxJSON & CtxJSON::CloseObject() return *this; } +// ------------------------------------------------------------------------------------------------ +CtxJSON & CtxJSON::ReopenObject() +{ + // If the last character is a comma then remove it + if (mOutput.back() == ',') + { + mOutput.pop_back(); + } + // If the last character is the object-end character then replace it with a comma + if (mOutput.back() == '}') + { + mOutput.back() = ','; + } + // Allow chaining + return *this; +} + // ------------------------------------------------------------------------------------------------ CtxJSON & CtxJSON::MakeKey() { @@ -225,6 +260,11 @@ CtxJSON & CtxJSON::MakeKey() { mOutput.push_back(':'); } + // Allow the hook to react + if (mKeyHook) + { + mKeyHook(*this); + } // Allow chaining return *this; } @@ -467,7 +507,7 @@ SQRESULT CtxJSON::SerializeTable(HSQUIRRELVM vm, SQInteger idx) // NOLINT(misc-n // ------------------------------------------------------------------------------------------------ SQRESULT CtxJSON::SerializeInstance(HSQUIRRELVM vm, SQInteger idx) { - sq_pushstring(vm, _SC("_tojson"), 7); + sq_pushstring(vm, mMetaMethod.c_str(), static_cast< SQInteger >(mMetaMethod.size())); // Attempt to retrieve the meta-method from the instance if(SQRESULT r = sq_get(vm, idx); SQ_FAILED(r)) { @@ -629,6 +669,8 @@ void CtxJSON::PushString(const SQChar * str) mOutput.append(str); mOutput.push_back('"'); mOutput.push_back(','); + // Allow the hook to know + mString.assign(str); } // ------------------------------------------------------------------------------------------------ @@ -638,6 +680,8 @@ void CtxJSON::PushString(const SQChar * str, size_t length) mOutput.append(str, length); mOutput.push_back('"'); mOutput.push_back(','); + // Allow the hook to know + mString.assign(str, length); } // ------------------------------------------------------------------------------------------------ @@ -678,6 +722,7 @@ void Register_JSON(HSQUIRRELVM vm) // Constructors .Ctor() .Ctor< bool >() + .Ctor< bool, StackStrF & >() // Meta-methods .SquirrelFunc(_SC("_typename"), &SqCtxJSON::Fn) // Properties diff --git a/module/Library/JSON.hpp b/module/Library/JSON.hpp index 474418b5..5cad12d4 100644 --- a/module/Library/JSON.hpp +++ b/module/Library/JSON.hpp @@ -5,12 +5,13 @@ #include "Library/IO/Buffer.hpp" // ------------------------------------------------------------------------------------------------ -#include +#include + +// ------------------------------------------------------------------------------------------------ #include #include #include - // ------------------------------------------------------------------------------------------------ namespace SqMod { @@ -35,6 +36,21 @@ struct CtxJSON */ uint32_t mDepth{0}; + /* -------------------------------------------------------------------------------------------- + * The meta-method name to use on objects. + */ + String mMetaMethod{"_tojson"}; + + /* -------------------------------------------------------------------------------------------- + * Last pushed string value. Can be used to heck for key name in the hook. + */ + String mString{}; + + /* -------------------------------------------------------------------------------------------- + * Internal utility used to monitor the existence of certain keys to allow overloading. + */ + std::function< void(CtxJSON&) > mKeyHook{}; + /* -------------------------------------------------------------------------------------------- * Default constructor. */ @@ -49,6 +65,26 @@ struct CtxJSON mObjectOverArray = ooa; } + /* -------------------------------------------------------------------------------------------- + * Explicit constructor. + */ + CtxJSON(bool ooa, StackStrF & mmname) noexcept + : CtxJSON() + { + mObjectOverArray = ooa; + // Allow custom metamethod names + mMetaMethod.assign(mmname.mPtr, static_cast< size_t >(mmname.mLen)); + } + + /* -------------------------------------------------------------------------------------------- + * Internal constructor. + */ + explicit CtxJSON(std::function< void(CtxJSON&) > && kh) noexcept + : CtxJSON() + { + mKeyHook = std::move(kh); + } + /* -------------------------------------------------------------------------------------------- * Copy constructor. */ @@ -135,6 +171,11 @@ struct CtxJSON */ CtxJSON & CloseArray(); + /* -------------------------------------------------------------------------------------------- + * Resume writing an array. + */ + CtxJSON & ReopenArray(); + /* -------------------------------------------------------------------------------------------- * Begin writing an object. */ @@ -145,6 +186,11 @@ struct CtxJSON */ CtxJSON & CloseObject(); + /* -------------------------------------------------------------------------------------------- + * Resume writing an object. + */ + CtxJSON & ReopenObject(); + /* -------------------------------------------------------------------------------------------- * Begin writing a key value. */