Skip to content

Instantly share code, notes, and snippets.

@phase
Created July 14, 2022 00:16
Show Gist options
  • Save phase/3205f8af061c691daef4507b5a16f724 to your computer and use it in GitHub Desktop.
Save phase/3205f8af061c691daef4507b5a16f724 to your computer and use it in GitHub Desktop.
pub const LoginPacket = struct {
id: u32,
x: u8,
y: u8,
z: u8,
};
pub const ByteBuf = struct {
fn write(_: *ByteBuf, comptime T: type, value: T) void {
std.debug.print("write({}, {})\n", .{T, value});
}
fn read(_: *ByteBuf, comptime T: type) T {
std.debug.print("read({})\n", .{T});
return 5;
}
};
// comptime function to build a packet serializer by reading the fields of a struct
fn packet_serializer(comptime T: type) type {
// return an anonymous struct
return struct {
// write a packet to a bytebuf
fn write(byteBuf: *ByteBuf, packet: T) void {
// compile-time type reflection
switch (@typeInfo(T)) {
.Struct => |*strct| {
// iterate over every field (at comptime)
inline for (strct.fields) |field| {
byteBuf.write(field.field_type, @field(packet, field.name));
}
},
else => unreachable, // T is not a struct, so we can't serialize it
}
}
// read a packet from a bytebuf
fn read(byteBuf: *ByteBuf) T {
var packet: T = undefined;
// compile-time type reflection
switch (@typeInfo(T)) {
.Struct => |*strct| {
// iterate over every field (at comptime)
inline for (strct.fields) |field| {
// write the read value to the packet
@field(packet, field.name) = byteBuf.read(field.field_type);
}
},
else => unreachable, // T is not a struct, so we can't serialize it
}
return packet;
}
};
}
test "packet serializer for LoginPacket" {
const LoginPacketSerializer: type = comptime packet_serializer(LoginPacket);
const byteBuf = ByteBuf{};
LoginPacketSerializer.write(byteBuf, .{.id = 5, .x = 1, .y = 2, .z = 3});
const packet = LoginPacketSerializer.read(byteBuf);
try expect(packet.id == 5);
try expect(packet.x == packet.y);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment