give the message serializer its own repo

This commit is contained in:
2024-04-14 12:33:17 +02:00
commit 4039239c16
6 changed files with 361 additions and 0 deletions

19
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.9...3.24 FATAL_ERROR)
project(solanaceae)
add_library(solanaceae_message_serializer
./solanaceae/message3/message_serializer.hpp
./solanaceae/message3/message_serializer.cpp
)
target_include_directories(solanaceae_message_serializer PUBLIC .)
target_compile_features(solanaceae_message_serializer PUBLIC cxx_std_17)
target_link_libraries(solanaceae_message_serializer PUBLIC
solanaceae_util
solanaceae_message3
nlohmann_json::nlohmann_json
)
########################################

View File

@@ -0,0 +1,120 @@
#include "./message_serializer.hpp"
#include <solanaceae/message3/components.hpp>
#include <solanaceae/contact/components.hpp>
#include <nlohmann/json.hpp>
#include <iostream>
static Contact3 findContactByID(Contact3Registry& cr, const std::vector<uint8_t>& id) {
// TODO: id lookup table, this is very inefficent
for (const auto& [c_it, id_it] : cr.view<Contact::Components::ID>().each()) {
if (id == id_it.data) {
return c_it;
}
}
return entt::null;
}
template<>
bool MessageSerializerNJ::component_get_json<Message::Components::ContactFrom>(MessageSerializerNJ& msc, const Handle h, nlohmann::json& j) {
const Contact3 c = h.get<Message::Components::ContactFrom>().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<Contact::Components::ID>(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<Contact::Components::ID>(c).data);
return true;
}
template<>
bool MessageSerializerNJ::component_emplace_or_replace_json<Message::Components::ContactFrom>(MessageSerializerNJ& msc, Handle h, const nlohmann::json& j) {
if (j.is_null()) {
std::cerr << "MSC warning: encountered null contact\n";
h.emplace_or_replace<Message::Components::ContactFrom>();
return true;
}
std::vector<uint8_t> id;
if (j.is_binary()) {
id = j.get_binary();
} else {
j["bytes"].get_to(id);
}
Contact3 other_c = findContactByID(msc.cr, id);
if (!msc.cr.valid(other_c)) {
// create sparse contact with id only
other_c = msc.cr.create();
msc.cr.emplace_or_replace<Contact::Components::ID>(other_c, id);
}
h.emplace_or_replace<Message::Components::ContactFrom>(other_c);
// TODO: should we return false if the contact is unknown??
return true;
}
template<>
bool MessageSerializerNJ::component_get_json<Message::Components::ContactTo>(MessageSerializerNJ& msc, const Handle h, nlohmann::json& j) {
const Contact3 c = h.get<Message::Components::ContactTo>().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<Contact::Components::ID>(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<Contact::Components::ID>(c).data);
return true;
}
template<>
bool MessageSerializerNJ::component_emplace_or_replace_json<Message::Components::ContactTo>(MessageSerializerNJ& msc, Handle h, const nlohmann::json& j) {
if (j.is_null()) {
std::cerr << "MSC warning: encountered null contact\n";
h.emplace_or_replace<Message::Components::ContactTo>();
return true;
}
std::vector<uint8_t> id;
if (j.is_binary()) {
id = j.get_binary();
} else {
j["bytes"].get_to(id);
}
Contact3 other_c = findContactByID(msc.cr, id);
if (!msc.cr.valid(other_c)) {
// create sparse contact with id only
other_c = msc.cr.create();
msc.cr.emplace_or_replace<Contact::Components::ID>(other_c, id);
}
h.emplace_or_replace<Message::Components::ContactTo>(other_c);
// TODO: should we return false if the contact is unknown??
return true;
}

View File

@@ -0,0 +1,87 @@
#pragma once
#include <entt/core/type_info.hpp>
#include <entt/container/dense_map.hpp>
#include <solanaceae/message3/registry_message_model.hpp>
#include <nlohmann/json_fwd.hpp>
struct MessageSerializerNJ {
using Registry = Message3Registry;
using Handle = Message3Handle;
Contact3Registry& cr;
// nlohmann
// json/msgpack
using serialize_fn = bool(*)(MessageSerializerNJ& msc, const Handle h, nlohmann::json& out);
entt::dense_map<entt::id_type, serialize_fn> _serl_json;
using deserialize_fn = bool(*)(MessageSerializerNJ& msc, Handle h, const nlohmann::json& in);
entt::dense_map<entt::id_type, deserialize_fn> _deserl_json;
template<typename T>
static bool component_get_json(MessageSerializerNJ&, const Handle h, nlohmann::json& j) {
if (h.template all_of<T>()) {
if constexpr (!std::is_empty_v<T>) {
j = h.template get<T>();
}
return true;
}
return false;
}
template<typename T>
static bool component_emplace_or_replace_json(MessageSerializerNJ&, Handle h, const nlohmann::json& j) {
if constexpr (std::is_empty_v<T>) {
h.template emplace_or_replace<T>(); // assert empty json?
} else {
h.template emplace_or_replace<T>(static_cast<T>(j));
}
return true;
}
void registerSerializer(serialize_fn fn, const entt::type_info& type_info) {
_serl_json[type_info.hash()] = fn;
}
template<typename CompType>
void registerSerializer(
serialize_fn fn = component_get_json<CompType>,
const entt::type_info& type_info = entt::type_id<CompType>()
) {
registerSerializer(fn, type_info);
}
void registerDeserializer(deserialize_fn fn, const entt::type_info& type_info) {
_deserl_json[type_info.hash()] = fn;
}
template<typename CompType>
void registerDeserializer(
deserialize_fn fn = component_emplace_or_replace_json<CompType>,
const entt::type_info& type_info = entt::type_id<CompType>()
) {
registerDeserializer(fn, type_info);
}
// TODO: deregister
};
// fwd
namespace Message::Components {
struct ContactFrom;
struct ContactTo;
}
// make specializations known
template<>
bool MessageSerializerNJ::component_get_json<Message::Components::ContactFrom>(MessageSerializerNJ& msc, const Handle h, nlohmann::json& j);
template<>
bool MessageSerializerNJ::component_emplace_or_replace_json<Message::Components::ContactFrom>(MessageSerializerNJ& msc, Handle h, const nlohmann::json& j);
template<>
bool MessageSerializerNJ::component_get_json<Message::Components::ContactTo>(MessageSerializerNJ& msc, const Handle h, nlohmann::json& j);
template<>
bool MessageSerializerNJ::component_emplace_or_replace_json<Message::Components::ContactTo>(MessageSerializerNJ& msc, Handle h, const nlohmann::json& j);