From 425decdf7e9284d15aa726e3ae96b9942fb0e3ea Mon Sep 17 00:00:00 2001 From: IronClawTrem Date: Sun, 16 Feb 2020 03:40:06 +0000 Subject: create tremded branch --- src/script/rapidjson/values.hpp | 245 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 src/script/rapidjson/values.hpp (limited to 'src/script/rapidjson/values.hpp') diff --git a/src/script/rapidjson/values.hpp b/src/script/rapidjson/values.hpp new file mode 100644 index 0000000..7fb3abe --- /dev/null +++ b/src/script/rapidjson/values.hpp @@ -0,0 +1,245 @@ +#ifndef __LUA_RAPIDJSON_TOLUAHANDLER_HPP__ +#define __LUA_RAPIDJSON_TOLUAHANDLER_HPP__ + +#include + + +#include "qcommon/q3_lauxlib.h" +#include "lua.hpp" +#include "rapidjson.h" + +#include "luax.hpp" +namespace values +{ + typedef rapidjson::Document::AllocatorType Allocator; + + int json_null(lua_State* L); + + inline bool isnull(lua_State* L, int idx) + { + lua_pushvalue(L, idx); // [value] + + json_null(L); // [value, json.null] + auto is = lua_rawequal(L, -1, -2) != 0; + lua_pop(L, 2); // [] + + return is; + } + + inline bool hasJsonType(lua_State* L, int idx, bool& isarray) + { + auto has = false; + if (lua_getmetatable(L, idx)) + { + // [metatable] + lua_getfield(L, -1, "__jsontype"); // [metatable, metatable.__jsontype] + if (lua_isstring(L, -1)) + { + size_t len; + auto s = lua_tolstring(L, -1, &len); + isarray = strncmp(s, "array", 6) == 0; + has = true; + } + lua_pop(L, 2); // [] + } + + return has; + } + + inline bool isarray(lua_State* L, int idx) + { + auto arr = false; + if (hasJsonType(L, idx, arr)) // any table with a meta field __jsontype set to 'array' are arrays + return arr; + + return luax::rawlen(L, idx) > 0; // any table has length > 0 are treat as array. + } + + /** + * Handle json SAX events and create Lua object. + */ + struct ToLuaHandler + { + explicit ToLuaHandler(lua_State* aL) : L(aL) + { stack_.reserve(32); } + + bool Null() + { + json_null(L); + context_.submit(L); + return true; + } + bool Bool(bool b) + { + lua_pushboolean(L, b); + context_.submit(L); + return true; + } + bool Int(int i) + { + lua_pushinteger(L, i); + context_.submit(L); + return true; + } + bool Uint(unsigned u) + { + if (sizeof(lua_Integer) > sizeof(unsigned int) || u <= static_cast(std::numeric_limits::max())) + lua_pushinteger(L, static_cast(u)); + else + lua_pushnumber(L, static_cast(u)); + context_.submit(L); + return true; + } + bool Int64(int64_t i) + { + if (sizeof(lua_Integer) >= sizeof(int64_t) || (i <= std::numeric_limits::max() && i >= std::numeric_limits::min())) + lua_pushinteger(L, static_cast(i)); + else + lua_pushnumber(L, static_cast(i)); + context_.submit(L); + return true; + } + bool Uint64(uint64_t u) + { + if (sizeof(lua_Integer) > sizeof(uint64_t) || u <= static_cast(std::numeric_limits::max())) + lua_pushinteger(L, static_cast(u)); + else + lua_pushnumber(L, static_cast(u)); + context_.submit(L); + return true; + } + bool Double(double d) + { + lua_pushnumber(L, static_cast(d)); + context_.submit(L); + return true; + } + bool RawNumber(const char* str, rapidjson::SizeType length, bool copy) + { + lua_getglobal(L, "tonumber"); + lua_pushlstring(L, str, length); + lua_call(L, 1, 1); + context_.submit(L); + return true; + } + bool String(const char* str, rapidjson::SizeType length, bool copy) + { + lua_pushlstring(L, str, length); + context_.submit(L); + return true; + } + bool StartObject() + { + lua_createtable(L, 0, 0); // [..., object] + + // mark as object. + luaL_getmetatable(L, "json.object"); //[..., object, json.object] + lua_setmetatable(L, -2); // [..., object] + + stack_.push_back(context_); + context_ = Ctx::Object(); + return true; + } + bool Key(const char* str, rapidjson::SizeType length, bool copy) const + { + lua_pushlstring(L, str, length); + return true; + } + bool EndObject(rapidjson::SizeType memberCount) + { + context_ = stack_.back(); + stack_.pop_back(); + context_.submit(L); + return true; + } + bool StartArray() + { + lua_createtable(L, 0, 0); + + // mark as array. + luaL_getmetatable(L, "json.array"); //[..., array, json.array] + lua_setmetatable(L, -2); // [..., array] + + stack_.push_back(context_); + context_ = Ctx::Array(); + return true; + } + bool EndArray(rapidjson::SizeType elementCount) + { + assert(elementCount == context_.index_); + context_ = stack_.back(); + stack_.pop_back(); + context_.submit(L); + return true; + } + private: + + + struct Ctx + { + Ctx() : index_(0), fn_(&topFn) {} + Ctx(const Ctx& rhs) : index_(rhs.index_), fn_(rhs.fn_) {} + + const Ctx& operator=(const Ctx& rhs) + { + if (this != &rhs) + { + index_ = rhs.index_; + fn_ = rhs.fn_; + } + return *this; + } + + static Ctx Object() + { return Ctx(&objectFn); } + + static Ctx Array() + { return Ctx(&arrayFn); } + + void submit(lua_State* L) + { fn_(L, this); } + + int index_; + + void(*fn_)(lua_State* L, Ctx* ctx); + + private: + explicit Ctx(void(*f)(lua_State* L, Ctx* ctx)) : index_(0), fn_(f) {} + + static void objectFn(lua_State* L, Ctx* ctx) + { lua_rawset(L, -3); } + + static void arrayFn(lua_State* L, Ctx* ctx) + { lua_rawseti(L, -2, ++ctx->index_); } + + static void topFn(lua_State* L, Ctx* ctx) {} + }; + + lua_State* L; + std::vector < Ctx > stack_; + Ctx context_; + }; + + namespace details + { + rapidjson::Value toValue(lua_State* L, int idx, int depth, Allocator& allocator); + } + + inline rapidjson::Value toValue(lua_State* L, int idx, Allocator& allocator) + { + return details::toValue(L, idx, 0, allocator); + } + + inline void toDocument(lua_State* L, int idx, rapidjson::Document* doc) + { + details::toValue(L, idx, 0, doc->GetAllocator()).Swap(*doc); + } + + inline void push(lua_State* L, const rapidjson::Value& v) + { + ToLuaHandler handler(L); + v.Accept(handler); + } +} + +#endif -- cgit