#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include "types.hpp" namespace net { namespace packet { using packet_header = std::tuple; template void decode_packet(std::span payload, T& t) { std::size_t offset = 0; boost::pfr::for_each_field(t, [&payload, &offset](auto& field, int i) { if (offset >= payload.size()) { throw std::runtime_error("Received invalid packet"); } offset += decode_field(payload.subspan(offset), field); }); if (offset < payload.size()) { throw std::runtime_error(std::format("{}: {}", offset, payload.size())); } } template std::vector encode_raw_packet(T& t) { std::vector payload; boost::pfr::for_each_field(t, [&payload](auto& field) { encode_field(payload, field); }); return payload; } template std::vector encode_packet(T& t) { return encode_raw_packet(t); } template std::vector encode_packet(T& t) { static constexpr auto chunk_size = 1024; std::array buffer; std::vector payload; int ret, flush; z_stream strm; auto raw_payload = encode_raw_packet(t); strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; ret = deflateInit(&strm, 15); if (ret != Z_OK) throw std::runtime_error("deflate init error"); strm.avail_in = raw_payload.size(); strm.next_in = raw_payload.data(); do { strm.avail_out = chunk_size; strm.next_out = reinterpret_cast(buffer.data()); ret = deflate(&strm, flush); assert(ret != Z_STREAM_ERROR); payload.insert(payload.end(), buffer.begin(), buffer.end()-strm.avail_out); } while (strm.avail_out == 0); assert(strm.avail_in == 0); /* all input will be used */ deflateEnd(&strm); return payload; } } }