From 1bfd04680e57d20b7b4e6edbeaaa85642c73d9f6 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Fri, 16 Feb 2024 16:29:37 +0100 Subject: [PATCH] refactor message serializer to allow access to eg contacts --- src/CMakeLists.txt | 2 + src/fragment_store/message_fragment_store.cpp | 4 +- src/fragment_store/message_fragment_store.hpp | 6 +- src/fragment_store/message_serializer.cpp | 94 +++++++++++++++++++ src/fragment_store/message_serializer.hpp | 85 +++++++++++++++++ 5 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 src/fragment_store/message_serializer.cpp create mode 100644 src/fragment_store/message_serializer.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6e3e87e..6540420 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,6 +19,8 @@ target_link_libraries(fragment_store PUBLIC ######################################## add_library(message_fragment_store + ./fragment_store/message_serializer.hpp + ./fragment_store/message_serializer.cpp ./fragment_store/message_fragment_store.hpp ./fragment_store/message_fragment_store.cpp ) diff --git a/src/fragment_store/message_fragment_store.cpp b/src/fragment_store/message_fragment_store.cpp index bc7804b..cecc02e 100644 --- a/src/fragment_store/message_fragment_store.cpp +++ b/src/fragment_store/message_fragment_store.cpp @@ -209,7 +209,7 @@ MessageFragmentStore::MessageFragmentStore( Contact3Registry& cr, RegistryMessageModel& rmm, FragmentStore& fs -) : _cr(cr), _rmm(rmm), _fs(fs) { +) : _cr(cr), _rmm(rmm), _fs(fs), _sc{_cr, {}, {}} { _rmm.subscribe(this, RegistryMessageModel_Event::message_construct); _rmm.subscribe(this, RegistryMessageModel_Event::message_updated); _rmm.subscribe(this, RegistryMessageModel_Event::message_destroy); @@ -292,7 +292,7 @@ float MessageFragmentStore::tick(float time_delta) { continue; } - s_cb_it->second({*reg, m}, j_entry[storage.type().name()]); + s_cb_it->second(_sc, {*reg, m}, j_entry[storage.type().name()]); } } diff --git a/src/fragment_store/message_fragment_store.hpp b/src/fragment_store/message_fragment_store.hpp index 8039470..559f477 100644 --- a/src/fragment_store/message_fragment_store.hpp +++ b/src/fragment_store/message_fragment_store.hpp @@ -4,6 +4,8 @@ #include "./fragment_store_i.hpp" #include "./fragment_store.hpp" +#include "./message_serializer.hpp" + #include #include @@ -36,10 +38,6 @@ namespace Fragment::Components { }; } // Fragment::Components -struct MessageSerializerCallbacks : public SerializerCallbacks { - // TODO: add contact and message reg, so entities can be looked up and be converted to fragment uids OR persistent ids -}; - // handles fragments for messages // on new message: assign fuid // on new and update: mark as fragment dirty diff --git a/src/fragment_store/message_serializer.cpp b/src/fragment_store/message_serializer.cpp new file mode 100644 index 0000000..98c6778 --- /dev/null +++ b/src/fragment_store/message_serializer.cpp @@ -0,0 +1,94 @@ +#include "./message_serializer.hpp" + +#include +#include + +#include + +#include + +template<> +bool MessageSerializerCallbacks::component_get_json(MessageSerializerCallbacks& msc, const Handle h, nlohmann::json& j) { + const Contact3 c = h.get().c; + if (!msc.cr.valid(c)) { + // while this is invalid registry state, it is valid serialization + j = nullptr; + std::cerr << "MSC warning: encountered invalid contact\n"; + return true; + } + + if (!msc.cr.all_of(c)) { + // unlucky, this contact is purely ephemeral + j = nullptr; + std::cerr << "MSC warning: encountered contact without ID\n"; + return true; + } + + j = nlohmann::json::binary(msc.cr.get(c).data); + + return true; +} +template<> +bool MessageSerializerCallbacks::component_emplace_or_replace_json(MessageSerializerCallbacks& msc, Handle h, const nlohmann::json& j) { + if (j.is_null()) { + std::cerr << "MSC warning: encountered null contact\n"; + h.emplace_or_replace(); + return true; + } + + const auto id = static_cast>(j); + + // TODO: id lookup table, this is very inefficent + for (const auto& [c_it, id_it] : msc.cr.view().each()) { + if (id == id_it.data) { + h.emplace_or_replace(c_it); + return true; + } + } + + // TODO: should we really return false if the contact is unknown?? + return false; +} + +template<> +bool MessageSerializerCallbacks::component_get_json(MessageSerializerCallbacks& msc, const Handle h, nlohmann::json& j) { + const Contact3 c = h.get().c; + if (!msc.cr.valid(c)) { + // while this is invalid registry state, it is valid serialization + j = nullptr; + std::cerr << "MSC warning: encountered invalid contact\n"; + return true; + } + + if (!msc.cr.all_of(c)) { + // unlucky, this contact is purely ephemeral + j = nullptr; + std::cerr << "MSC warning: encountered contact without ID\n"; + return true; + } + + j = nlohmann::json::binary(msc.cr.get(c).data); + + return true; +} +template<> +bool MessageSerializerCallbacks::component_emplace_or_replace_json(MessageSerializerCallbacks& msc, Handle h, const nlohmann::json& j) { + if (j.is_null()) { + std::cerr << "MSC warning: encountered null contact\n"; + h.emplace_or_replace(); + return true; + } + + const auto id = static_cast>(j); + + // TODO: id lookup table, this is very inefficent + for (const auto& [c_it, id_it] : msc.cr.view().each()) { + if (id == id_it.data) { + h.emplace_or_replace(c_it); + return true; + } + } + + // TODO: should we really return false if the contact is unknown?? + return false; +} diff --git a/src/fragment_store/message_serializer.hpp b/src/fragment_store/message_serializer.hpp new file mode 100644 index 0000000..70d6fcd --- /dev/null +++ b/src/fragment_store/message_serializer.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include +#include + +#include + +#include + +struct MessageSerializerCallbacks { + using Registry = Message3Registry; + using Handle = Message3Handle; + + Contact3Registry& cr; + + // nlohmann + // json/msgpack + using serialize_json_fn = bool(*)(MessageSerializerCallbacks& msc, const Handle h, nlohmann::json& out); + entt::dense_map _serl_json; + + using deserialize_json_fn = bool(*)(MessageSerializerCallbacks& msc, Handle h, const nlohmann::json& in); + entt::dense_map _deserl_json; + + template + static bool component_get_json(MessageSerializerCallbacks&, const Handle h, nlohmann::json& j) { + if (h.template all_of()) { + if constexpr (!std::is_empty_v) { + j = h.template get(); + } + return true; + } + + return false; + } + + template + static bool component_emplace_or_replace_json(MessageSerializerCallbacks&, Handle h, const nlohmann::json& j) { + if constexpr (std::is_empty_v) { + h.template emplace_or_replace(); // assert empty json? + } else { + h.template emplace_or_replace(static_cast(j)); + } + return true; + } + + void registerSerializerJson(serialize_json_fn fn, const entt::type_info& type_info) { + _serl_json[type_info.hash()] = fn; + } + + template + void registerSerializerJson( + serialize_json_fn fn = component_get_json, + const entt::type_info& type_info = entt::type_id() + ) { + registerSerializerJson(fn, type_info); + } + + void registerDeSerializerJson(deserialize_json_fn fn, const entt::type_info& type_info) { + _deserl_json[type_info.hash()] = fn; + } + + template + void registerDeSerializerJson( + deserialize_json_fn fn = component_emplace_or_replace_json, + const entt::type_info& type_info = entt::type_id() + ) { + registerDeSerializerJson(fn, type_info); + } +}; + +// fwd +namespace Message::Components { +struct ContactFrom; +struct ContactTo; +} + +// make specializations known +template<> +bool MessageSerializerCallbacks::component_get_json(MessageSerializerCallbacks& msc, const Handle h, nlohmann::json& j); +template<> +bool MessageSerializerCallbacks::component_emplace_or_replace_json(MessageSerializerCallbacks& msc, Handle h, const nlohmann::json& j); +template<> +bool MessageSerializerCallbacks::component_get_json(MessageSerializerCallbacks& msc, const Handle h, nlohmann::json& j); +template<> +bool MessageSerializerCallbacks::component_emplace_or_replace_json(MessageSerializerCallbacks& msc, Handle h, const nlohmann::json& j);