#pragma once #include "io/Write.hpp" #include "io/Read.hpp" #include #include #include namespace tw::net { class Serialization; template class Serializer final { public: static_assert(sizeof(T), "Invalid type for serialization"); static bool serialize(tw::net::Serialization& buffer, T& value); }; template concept Serializable = requires(tw::net::Serialization& b, T& t){ Serializer::serialize(b, t); }; /** * Handles serialization of data */ class Serialization { union { Write* m_writeable; Read* m_readable; } m_io; bool m_is_reading; Serialization(Write* writeable) : m_io({ .m_writeable = writeable }), m_is_reading(false) { } Serialization(Read* writeable) : m_io({ .m_readable = writeable }), m_is_reading(true) { } public: static Serialization reading(Read* read) { return Serialization(read); } static Serialization writing(Write* writeable) { return Serialization(writeable); } const bool is_reading() const { return m_is_reading; } template bool serialize(T& value) { return Serializer::serialize(*this, value); } /** * Special implementation that supports pointers. Useful for numeric types. */ template bool serialize(T* value, std::enable_if::is_integer, T>::type* = 0) { // TODO: enable only if trivially copyable // if constexpr (std::is_trivially_copyable_v) { // if(m_is_reading) { // const std::string packet_name = typeid(T).name(); // return m_io.m_readable->read(std::as_writable_bytes(std::span{value, 1})); // } else { // auto bytes = std::as_writable_bytes(std::span{value, 1}); // size_t num_writen = m_io.m_writeable->write(bytes); // spdlog::info("Pico"); // return true; // } // } else { // throw std::runtime_error("Cannot serialize non-trivially copyable type"); // } return true; } bool serialize(float* target) { union { float floating; unsigned int integer; } float_val; float_val.floating = *target; bool result = serialize(&float_val.integer); *target = float_val.floating; return result; } bool serialize(char* buffer, size_t length) { // if(m_is_reading) { // return m_io.m_readable->read(std::as_writable_bytes(std::span{buffer, length})); // } else { // return m_io.m_writeable->write(std::as_writable_bytes(std::span{buffer, length})); // } return true; } void flush() { if(!m_is_reading) { m_io.m_writeable->flush(); } } }; }