1const mem = @import("std").mem;23/// WriteBuffer adds support allows writing bytes to an underlying buffer4/// with safety-checked undefined behaviour. That is, the caller should5/// check in advance whether sufficient space is available via6/// WriteBuffer.capacity().7pub const WriteBuffer = struct {8 slice: []u8,9 pos: usize = 0,1011 pub fn serialized(self: *WriteBuffer) []u8 {12 return self.slice[0..self.pos];13 }1415 pub fn capacity(self: *WriteBuffer) usize {16 return self.slice.len - self.pos;17 }1819 pub fn bytes(self: *WriteBuffer, buf: []const u8) void {20 // mem.copy does provide us with safety-checked21 // undefined behaviour. Thus we don't need to check22 // the capacity explicitly here.23 @memcpy(self.slice[self.pos .. self.pos + buf.len], buf);24 self.pos += buf.len;25 }2627 fn write(self: *WriteBuffer, ptr: anytype) void {28 self.bytes(mem.asBytes(ptr));29 }3031 pub fn byte(self: *WriteBuffer, b: u8) void {32 self.write(&b);33 }3435 pub fn half(self: *WriteBuffer, h: u16) void {36 self.write(&h);37 }3839 pub fn word(self: *WriteBuffer, w: u32) void {40 self.write(&w);41 }42};4344pub const ReadBuffer = struct {45 slice: []const u8,4647 pub fn length(self: *ReadBuffer) usize {48 return self.slice.len;49 }5051 pub fn remaining(self: *ReadBuffer) []const u8 {52 return self.slice;53 }5455 pub fn bytes(self: *ReadBuffer, numBytes: usize) !([]const u8) {56 if (self.slice.len < numBytes)57 return error.OutOfBounds;5859 const result = self.slice[0..numBytes];60 self.slice = self.slice[numBytes..];61 return result;62 }6364 fn read(self: *ReadBuffer, comptime T: type, dest: anytype) !void {65 const slice = try self.bytes(@sizeOf(T));66 dest.* = @bitCast(slice[0..@sizeOf(T)].*);67 }6869 pub fn byte(self: *ReadBuffer) !u8 {70 var r: u8 = undefined;71 try self.read(u8, &r);72 return r;73 }7475 pub fn half(self: *ReadBuffer) !u16 {76 var r: u16 = undefined;77 try self.read(u16, &r);78 return r;79 }8081 pub fn word(self: *ReadBuffer) !u32 {82 var r: u32 = undefined;83 try self.read(u32, &r);84 return r;85 }86};