From 8e0cdee80b00e2d7bde723f4a66dc9a57aee7bc2 Mon Sep 17 00:00:00 2001 From: Cora <17833654450@163.com> Date: Tue, 4 Aug 2026 00:03:16 +0800 Subject: [PATCH 1/7] rename `SerdeBase::seralize` to `SerdeBase::to_string` --- include/gkit/core/reflect/serdebase.hpp | 4 ++-- src/core/reflect/serdebase.cpp | 4 ++-- test/core/reflect/test_serdebase.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/gkit/core/reflect/serdebase.hpp b/include/gkit/core/reflect/serdebase.hpp index a429633..633afaa 100644 --- a/include/gkit/core/reflect/serdebase.hpp +++ b/include/gkit/core/reflect/serdebase.hpp @@ -26,12 +26,12 @@ namespace gkit::core::reflect { * @throws std::invalid_argument if the id is not available. * @return Empty string when the object tree cannot be built. */ - [[nodiscard]] auto seralize(const ObjectId& id) -> std::string; + [[nodiscard]] auto to_string(const ObjectId& id) -> std::string; /** * @brief Serialize a single value node (with optional key). */ - [[nodiscard]] auto seralize(const std::string& key, const Value& v) -> std::string; + [[nodiscard]] auto to_string(const std::string& key, const Value& v) -> std::string; // ===================================================================== // Format hooks (pure virtual) diff --git a/src/core/reflect/serdebase.cpp b/src/core/reflect/serdebase.cpp index 990fdb7..5df7fb5 100644 --- a/src/core/reflect/serdebase.cpp +++ b/src/core/reflect/serdebase.cpp @@ -46,7 +46,7 @@ namespace gkit::core::reflect { } // namespace - auto SerdeBase::seralize(const ObjectId& id) -> std::string { + auto SerdeBase::to_string(const ObjectId& id) -> std::string { if (!id.available()) { throw std::invalid_argument("id is not available"); } @@ -59,7 +59,7 @@ namespace gkit::core::reflect { return render_node(ss.root(), *this); } - auto SerdeBase::seralize(const std::string& key, const Value& v) -> std::string { + auto SerdeBase::to_string(const std::string& key, const Value& v) -> std::string { return render_node(SerdeNode(key, v), *this); } diff --git a/test/core/reflect/test_serdebase.cpp b/test/core/reflect/test_serdebase.cpp index e36ecb8..e03be21 100644 --- a/test/core/reflect/test_serdebase.cpp +++ b/test/core/reflect/test_serdebase.cpp @@ -78,7 +78,7 @@ auto main() -> int { SeralizeObject::regist_method(); auto json = Json(); auto obj = gkit::core::UniqueObject::create(); - auto serde_str = json.seralize(obj.get_id()); + auto serde_str = json.to_string(obj.get_id()); std::cout << serde_str << '\n'; const auto expect = @@ -91,14 +91,14 @@ auto main() -> int { // ObjectId values do not participate in (de)serialization for now. auto obj2 = gkit::core::UniqueObject::create(); - const auto ref_str = json.seralize("ref", Value(obj2.get_id())); + const auto ref_str = json.to_string("ref", Value(obj2.get_id())); if (!ref_str.empty()) { std::cerr << "expected ObjectId to be skipped, got: " << ref_str << '\n'; return 1; } const gkit::core::Array mixed = {Value(1), Value(obj2.get_id()), Value(2)}; - const auto mixed_str = json.seralize("mixed", Value(mixed)); + const auto mixed_str = json.to_string("mixed", Value(mixed)); if (mixed_str != "\"mixed\":[1,2]") { std::cerr << "unexpected mixed array output: " << mixed_str << '\n'; return 1; From 8082ce8261020cf041a47d5eb21634f556dbbc57 Mon Sep 17 00:00:00 2001 From: Cora <17833654450@163.com> Date: Tue, 4 Aug 2026 14:47:53 +0800 Subject: [PATCH 2/7] add default constructor for SerdeStruct --- src/core/reflect/seralize.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/reflect/seralize.hpp b/src/core/reflect/seralize.hpp index d286784..256d87c 100644 --- a/src/core/reflect/seralize.hpp +++ b/src/core/reflect/seralize.hpp @@ -33,9 +33,10 @@ namespace gkit::core::reflect { class SerdeStruct final { bool available_flag = false; - std::unique_ptr serde_root{}; + std::unique_ptr serde_root = nullptr; public: + SerdeStruct() = default; explicit SerdeStruct(Value v) noexcept; explicit SerdeStruct(const ObjectId v) noexcept; ~SerdeStruct() = default; From 36fa580f4e5d62ae1416fae5e4d69961c20ac865 Mon Sep 17 00:00:00 2001 From: Cora <17833654450@163.com> Date: Tue, 4 Aug 2026 14:52:41 +0800 Subject: [PATCH 3/7] add method `SerdeStruct::from` --- src/core/reflect/seralize.cpp | 11 ++++++++++- src/core/reflect/seralize.hpp | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/core/reflect/seralize.cpp b/src/core/reflect/seralize.cpp index 28fa482..3df6224 100644 --- a/src/core/reflect/seralize.cpp +++ b/src/core/reflect/seralize.cpp @@ -1,6 +1,7 @@ #include "core/reflect/seralize.hpp" #include "core/object_pool.hpp" +#include "gkit/core/object_id.hpp" #include "gkit/core/reflect/registry.hpp" #include "gkit/core/value.hpp" @@ -34,11 +35,19 @@ namespace gkit::core::reflect { * SerdeStruct */ SerdeStruct::SerdeStruct(Value v) noexcept { // NOLINT(performance-unnecessary-value-param) + this->from(std::move(v)); + } + + SerdeStruct::SerdeStruct(const ObjectId v) noexcept { + this->from(v); + } + + auto SerdeStruct::from(Value v) noexcept -> void { // NOLINT(performance-unnecessary-value-param) this->serde_root = std::make_unique("", std::move(v)); this->available_flag = true; } - SerdeStruct::SerdeStruct(const ObjectId v) noexcept { + auto SerdeStruct::from(ObjectId v) noexcept -> void { if (!v.available()) return; auto* obj_ptr = ObjectPool::instance().deref_from(v); diff --git a/src/core/reflect/seralize.hpp b/src/core/reflect/seralize.hpp index 256d87c..577daa6 100644 --- a/src/core/reflect/seralize.hpp +++ b/src/core/reflect/seralize.hpp @@ -41,6 +41,8 @@ namespace gkit::core::reflect { explicit SerdeStruct(const ObjectId v) noexcept; ~SerdeStruct() = default; + auto from(Value v) noexcept -> void; + auto from(const ObjectId v) noexcept -> void; [[nodiscard]] inline auto available() -> bool { return this->available_flag; } [[nodiscard]] inline auto root() const -> const SerdeNode& { return *this->serde_root; } }; From 1148548bcac16d3876fe3482afc9586914e2cbf3 Mon Sep 17 00:00:00 2001 From: Cora <17833654450@163.com> Date: Tue, 4 Aug 2026 15:02:51 +0800 Subject: [PATCH 4/7] add SerdeStruct::operator[] --- src/core/reflect/seralize.cpp | 11 +++++++++++ src/core/reflect/seralize.hpp | 3 +++ 2 files changed, 14 insertions(+) diff --git a/src/core/reflect/seralize.cpp b/src/core/reflect/seralize.cpp index 3df6224..2a7c40a 100644 --- a/src/core/reflect/seralize.cpp +++ b/src/core/reflect/seralize.cpp @@ -6,6 +6,7 @@ #include "gkit/core/value.hpp" #include +#include #include #include @@ -42,6 +43,16 @@ namespace gkit::core::reflect { this->from(v); } + auto SerdeStruct::operator[](const std::string& key) -> Value& { + for (const auto& node : this->serde_root->get_children()) { + if (node->get_key() == key) { + return node->get_value(); + } + } + + throw std::invalid_argument("element not found"); + } + auto SerdeStruct::from(Value v) noexcept -> void { // NOLINT(performance-unnecessary-value-param) this->serde_root = std::make_unique("", std::move(v)); this->available_flag = true; diff --git a/src/core/reflect/seralize.hpp b/src/core/reflect/seralize.hpp index 577daa6..76b06f2 100644 --- a/src/core/reflect/seralize.hpp +++ b/src/core/reflect/seralize.hpp @@ -25,6 +25,7 @@ namespace gkit::core::reflect { [[nodiscard]] inline auto get_key() const -> const std::string& { return this->key; } [[nodiscard]] inline auto get_type() const -> Type { return this->type; } + [[nodiscard]] inline auto get_value() -> Value& { return this->value; } [[nodiscard]] inline auto get_value() const -> const Value& { return this->value; } [[nodiscard]] inline auto get_children() const -> const std::vector>& { return this->children; @@ -41,6 +42,8 @@ namespace gkit::core::reflect { explicit SerdeStruct(const ObjectId v) noexcept; ~SerdeStruct() = default; + auto operator[](const std::string& key) -> Value&; + auto from(Value v) noexcept -> void; auto from(const ObjectId v) noexcept -> void; [[nodiscard]] inline auto available() -> bool { return this->available_flag; } From ddd374f0c8c45ef673dd73f0c2f05a48b22e4d41 Mon Sep 17 00:00:00 2001 From: Cora <17833654450@163.com> Date: Tue, 4 Aug 2026 15:38:57 +0800 Subject: [PATCH 5/7] add SerdeBase::from --- include/gkit/core/reflect/serdebase.hpp | 26 +++++++++++++----------- src/core/reflect/serdebase.cpp | 27 ++++++++++++++++++------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/include/gkit/core/reflect/serdebase.hpp b/include/gkit/core/reflect/serdebase.hpp index 633afaa..7f9537b 100644 --- a/include/gkit/core/reflect/serdebase.hpp +++ b/include/gkit/core/reflect/serdebase.hpp @@ -3,6 +3,7 @@ #include "gkit/core/object_id.hpp" #include "gkit/core/value.hpp" +#include #include #include @@ -16,35 +17,36 @@ namespace gkit::core::reflect { * (Json / Xml / Toml ...) by overriding the wrapper / gap / leaf hooks. */ class SerdeBase { + struct SerdeData; + std::unique_ptr data; + public: using WrapperPair = std::pair; - virtual ~SerdeBase() = default; + SerdeBase(); + virtual ~SerdeBase(); - /** - * @brief Serialize an object (by id) into the target format. - * @throws std::invalid_argument if the id is not available. - * @return Empty string when the object tree cannot be built. - */ - [[nodiscard]] auto to_string(const ObjectId& id) -> std::string; + auto from(const ObjectId& id) -> void; + auto from(const Value& v) -> void; /** - * @brief Serialize a single value node (with optional key). + * @brief Serialize serdedata to string. + * @return Empty string when the SerdeBase cannot be built. */ - [[nodiscard]] auto to_string(const std::string& key, const Value& v) -> std::string; + [[nodiscard]] auto to_string() const noexcept -> std::string; // ===================================================================== // Format hooks (pure virtual) // ===================================================================== /// @brief Begin/end delimiters around a node (keyed or unkeyed). - virtual auto wrapper(Type type, const std::string& key) -> WrapperPair = 0; + virtual auto wrapper(Type type, const std::string& key) const -> WrapperPair = 0; /// @brief Separator between sibling elements of a container. - virtual auto element_gap(Type type) -> std::string = 0; + virtual auto element_gap(Type type) const -> std::string = 0; /// @brief Encode a leaf value into the target format. - virtual auto leaf_value(const Value& v) -> std::string = 0; + virtual auto leaf_value(const Value& v) const -> std::string = 0; }; } // namespace gkit::core::reflect diff --git a/src/core/reflect/serdebase.cpp b/src/core/reflect/serdebase.cpp index 5df7fb5..f7070b0 100644 --- a/src/core/reflect/serdebase.cpp +++ b/src/core/reflect/serdebase.cpp @@ -1,15 +1,18 @@ #include "gkit/core/reflect/serdebase.hpp" #include "core/reflect/seralize.hpp" +#include "seralize.hpp" +#include #include #include +#include namespace gkit::core::reflect { namespace { - auto render_node(const SerdeNode& node, SerdeBase& base) -> std::string { + auto render_node(const SerdeNode& node, const SerdeBase& base) -> std::string { // ObjectId values do not participate in (de)serialization for now. if (node.get_type() == Type::ObjectId) { return {}; @@ -46,12 +49,26 @@ namespace gkit::core::reflect { } // namespace - auto SerdeBase::to_string(const ObjectId& id) -> std::string { + struct SerdeBase::SerdeData { + SerdeStruct ss {}; + }; + + SerdeBase::SerdeBase() : data(std::make_unique()) {} + SerdeBase::~SerdeBase() {} + + auto SerdeBase::from(const ObjectId& id) -> void { if (!id.available()) { throw std::invalid_argument("id is not available"); } + this->data->ss.from(id); + } - SerdeStruct ss(id); + auto SerdeBase::from(const Value& v) -> void { + this->data->ss.from(v); + } + + auto SerdeBase::to_string() const noexcept -> std::string { + auto& ss = this->data->ss; if (!ss.available()) { return {}; } @@ -59,8 +76,4 @@ namespace gkit::core::reflect { return render_node(ss.root(), *this); } - auto SerdeBase::to_string(const std::string& key, const Value& v) -> std::string { - return render_node(SerdeNode(key, v), *this); - } - } // namespace gkit::core::reflect From f74895c35eb414d7675d97199fd39de2fde03b05 Mon Sep 17 00:00:00 2001 From: Cora <17833654450@163.com> Date: Tue, 4 Aug 2026 15:40:35 +0800 Subject: [PATCH 6/7] update test_serdebase --- test/core/reflect/test_serdebase.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/test/core/reflect/test_serdebase.cpp b/test/core/reflect/test_serdebase.cpp index e03be21..e161fba 100644 --- a/test/core/reflect/test_serdebase.cpp +++ b/test/core/reflect/test_serdebase.cpp @@ -15,7 +15,7 @@ class SeralizeObject : public gkit::core::Object { std::string str = "Hello my girl"; gkit::core::Array arr = {Value(100), Value(200.f), Value("300")}; - gkit::core::Map map = {{"map_num", Value(100)}, {"map_fnum", Value(200.f)}, {"map_str", Value("")}}; + gkit::core::Map map = {{"map_num", Value(100)}, {"map_fnum", Value(200.f)}, {"map_str", Value("str")}}; public: static const char* c_name; @@ -33,7 +33,7 @@ class SeralizeObject : public gkit::core::Object { const char* SeralizeObject::c_name = "SeralizeObject"; class Json final : public SerdeBase { - auto wrapper(gkit::core::Type type, const std::string& key) -> WrapperPair override { + auto wrapper(gkit::core::Type type, const std::string& key) const -> WrapperPair override { std::string begin; if (!key.empty()) { begin += "\"" + key + "\":"; @@ -51,9 +51,9 @@ class Json final : public SerdeBase { return {begin, end}; } - auto element_gap(gkit::core::Type /*type*/) -> std::string override { return ","; } + auto element_gap(gkit::core::Type /*type*/) const -> std::string override { return ","; } - auto leaf_value(const Value& v) -> std::string override { + auto leaf_value(const Value& v) const -> std::string override { switch (v.type()) { case gkit::core::Type::String: { return "\"" + v.as_string() + "\""; @@ -76,13 +76,14 @@ class Json final : public SerdeBase { auto main() -> int { SeralizeObject::regist_method(); - auto json = Json(); - auto obj = gkit::core::UniqueObject::create(); - auto serde_str = json.to_string(obj.get_id()); + auto json = Json(); + auto obj = gkit::core::UniqueObject::create(); + json.from(obj.get_id()); + auto serde_str = json.to_string(); std::cout << serde_str << '\n'; const auto expect = - R"({"num":10,"f_num":20.000000,"str":"Hello my girl","arr":[100,200.000000,"300"],"map":{"map_fnum":200.000000,"map_num":100,"map_str":""}})"; + R"({"num":10,"f_num":20.000000,"str":"Hello my girl","arr":[100,200.000000,"300"],"map":{"map_fnum":200.000000,"map_num":100,"map_str":"str"}})"; if (serde_str != expect) { std::cerr << "unexpected output:\n got: " << serde_str << '\n' << " expected: " << expect << '\n'; return 1; @@ -90,16 +91,17 @@ auto main() -> int { // ObjectId values do not participate in (de)serialization for now. auto obj2 = gkit::core::UniqueObject::create(); - - const auto ref_str = json.to_string("ref", Value(obj2.get_id())); + json.from(Value(obj2.get_id())); + const auto ref_str = json.to_string(); if (!ref_str.empty()) { std::cerr << "expected ObjectId to be skipped, got: " << ref_str << '\n'; return 1; } const gkit::core::Array mixed = {Value(1), Value(obj2.get_id()), Value(2)}; - const auto mixed_str = json.to_string("mixed", Value(mixed)); - if (mixed_str != "\"mixed\":[1,2]") { + json.from(Value(mixed)); + const auto mixed_str = json.to_string(); + if (mixed_str != "[1,2]") { std::cerr << "unexpected mixed array output: " << mixed_str << '\n'; return 1; } From 012d8ab27549c361c5eb5259dd547ee748de8b76 Mon Sep 17 00:00:00 2001 From: Cora <17833654450@163.com> Date: Tue, 4 Aug 2026 15:46:54 +0800 Subject: [PATCH 7/7] add comment for SerdeBase::from --- include/gkit/core/reflect/serdebase.hpp | 9 +++++++++ src/core/reflect/serdebase.cpp | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/include/gkit/core/reflect/serdebase.hpp b/include/gkit/core/reflect/serdebase.hpp index 7f9537b..e87ba8d 100644 --- a/include/gkit/core/reflect/serdebase.hpp +++ b/include/gkit/core/reflect/serdebase.hpp @@ -26,7 +26,16 @@ namespace gkit::core::reflect { SerdeBase(); virtual ~SerdeBase(); + /** + * @brief Serialize an object to serdedata + * @throw @ref std::invalid_argument, if objectid is invalid + */ auto from(const ObjectId& id) -> void; + + /** + * @brief Serialize a value to serdedata + * @throw @ref std::invalid_argument, if value is null. + */ auto from(const Value& v) -> void; /** diff --git a/src/core/reflect/serdebase.cpp b/src/core/reflect/serdebase.cpp index f7070b0..2b58079 100644 --- a/src/core/reflect/serdebase.cpp +++ b/src/core/reflect/serdebase.cpp @@ -1,6 +1,7 @@ #include "gkit/core/reflect/serdebase.hpp" #include "core/reflect/seralize.hpp" +#include "gkit/core/value.hpp" #include "seralize.hpp" #include @@ -60,10 +61,15 @@ namespace gkit::core::reflect { if (!id.available()) { throw std::invalid_argument("id is not available"); } + this->data->ss.from(id); } auto SerdeBase::from(const Value& v) -> void { + if (v.type() == Type::Null) { + throw std::invalid_argument("id is not available"); + } + this->data->ss.from(v); }