1
0
Fork 0
Univerxel/src/core/net/io.hpp

140 lines
3.7 KiB
C++

#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<typename D>
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<typename D>
[[nodiscard]]
static data::out_buffer Of(net::client_packet_type type, const D& data) {
return Of(type, &data, sizeof(data));
}
template<typename D>
[[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<typename D>
const D* read() {
return buffer.cur + sizeof(D) <= buffer.size() ?
(const D*)buffer.readFrom(sizeof(D)) : nullptr;
}
template<typename D>
bool read(D& out) {
const auto ptr = read<D>();
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;
};
}