#pragma once #include "data.hpp" #include "../data/mem.hpp" namespace net { //TODO: preallocate static data pool /// Write allocated packets class PacketWriter final { public: PacketWriter(size_t size): buffer((uint8_t*)malloc(size), size) { } PacketWriter(uint8_t type, size_t data_size): PacketWriter(sizeof(type) + data_size) { write(type); } PacketWriter(net::client_packet_type type, size_t data_size): PacketWriter((uint8_t)type, data_size) { } PacketWriter(net::server_packet_type type, size_t data_size): PacketWriter((uint8_t)type, data_size) { } ~PacketWriter() { if (buffer.ptr != nullptr) free(buffer.ptr); } void write(const void* data, size_t len) { buffer.write((uint8_t*)data, len); } template void write(const D& d) { write(&d, sizeof(d)); } struct varying_part { varying_part(data::in_view &buffer): buffer(buffer), visible_size(0) { } ~varying_part() { buffer.siz = buffer.cur + visible_size; buffer.cur = buffer.siz; } data::in_view &buffer; size_t visible_size; constexpr size_t size() const { return visible_size; } void* data() { return buffer.writeTo(0); } void reserve(size_t target) { if (target >= buffer.siz - buffer.cur) { auto old = buffer.ptr; buffer.ptr = (uint8_t*)malloc(target); memcpy(buffer.ptr, old, buffer.siz); free(old); buffer.siz = target; } } void resize(size_t target) { reserve(target); visible_size = target; } }; /// Only from resize, write, resize down varying_part varying() { return varying_part(buffer); } bool isFull() const { return buffer.isDone(); } [[nodiscard]] data::out_buffer finish() { assert(isFull()); data::out_buffer cpy(buffer.ptr, buffer.siz); buffer.ptr = nullptr; buffer.siz = 0; return cpy; } [[nodiscard]] static data::out_buffer Of(net::client_packet_type type, const void* data, size_t size) { auto packet = PacketWriter(type, size); packet.write(data, size); return packet.finish(); } [[nodiscard]] static data::out_buffer Of(net::server_packet_type type, const void* data, size_t size) { auto packet = PacketWriter(type, size); packet.write(data, size); return packet.finish(); } template [[nodiscard]] static data::out_buffer Of(net::client_packet_type type, const D& data) { return Of(type, &data, sizeof(data)); } template [[nodiscard]] static data::out_buffer Of(net::server_packet_type type, const D& data) { return Of(type, &data, sizeof(data)); } private: data::in_view buffer; }; class PacketReader final { public: PacketReader(const data::out_view& buf): buffer(buf) { } template const D* read() { return buffer.cur + sizeof(D) <= buffer.size() ? (const D*)buffer.readFrom(sizeof(D)) : nullptr; } template bool read(D& out) { const auto ptr = read(); if (ptr == nullptr) return false; out = *ptr; return true; } bool skip(size_t size) { buffer.readFrom(size); return !isFull(); } data::out_view readAll() { const size_t remain = buffer.size() - buffer.cur; return data::out_view(buffer.readFrom(remain), remain); } bool isFull() const { return buffer.isDone(); } private: data::out_view buffer; }; }