//! Wire-format I/O helpers. //! //! These are sometimes very thin layers over standard `std.Io.Writer` //! but its to help ensure consistency in our behavior and avoid some //! pitfalls. const std = @import("std"); const testing = std.testing; /// writeInt ensures we write in little-endian since that is our /// standard form. pub fn writeInt( writer: *std.Io.Writer, comptime T: type, value: T, ) std.Io.Writer.Error!void { try writer.writeInt(T, value, .little); } /// Read a little-endian integer. /// /// This avoids `takeInt` because at the time of writing this the underlying /// implementation uses `takeArray` which asserts that the reader buffer /// is as large as T. Our approach works with caller-selected buffers that /// may be smaller. pub fn readInt( reader: *std.Io.Reader, comptime T: type, ) std.Io.Reader.Error!T { var buf: [@sizeOf(T)]u8 = undefined; try reader.readSliceAll(&buf); return std.mem.readInt(T, &buf, .little); } test "integer round trip with a one-byte reader buffer" { var encoded: [6]u8 = undefined; var writer: std.Io.Writer = .fixed(&encoded); try writeInt(&writer, u16, 0x1234); try writeInt(&writer, u32, 0x56789abc); // Keep the reader buffer smaller than either integer to verify readInt // does not inherit std.Io.Reader.takeInt's buffer-size requirement. var source: std.Io.Reader = .fixed(&encoded); var buf: [1]u8 = undefined; var limited = source.limited(.unlimited, &buf); try testing.expectEqual( @as(u16, 0x1234), try readInt(&limited.interface, u16), ); try testing.expectEqual( @as(u32, 0x56789abc), try readInt(&limited.interface, u32), ); }