Skip to content

Instantly share code, notes, and snippets.

@ssteinbach
Last active September 12, 2025 21:55
Show Gist options
  • Select an option

  • Save ssteinbach/ef2b57c960bb03fc6017f51e421ee72d to your computer and use it in GitHub Desktop.

Select an option

Save ssteinbach/ef2b57c960bb03fc6017f51e421ee72d to your computer and use it in GitHub Desktop.
Zig "Writergate" 0.15.1 Migration Links and Notes
const std = @import("std");
const ENDIAN = std.builtin.Endian.little;
/// takes a reader and reads some data out of the reader, returns the number of
/// bytes read
pub fn example_func_that_takes_a_reader(
reader: *std.Io.Reader,
) !u8
{
var buf:[1]f32 = undefined;
try reader.readSliceAll(std.mem.asBytes(&buf));
std.debug.print("buf: {d}\n", .{ buf[0] });
return 0;
}
/// example data structure to serialize/deserialize -- note that to use
/// writeStruct requires struct to be packed
const ExamplePacked = packed struct {
some_float: f32,
some_int: u32,
};
/// non-packed example to test
const ExampleNonPacked = struct {
some_float: f32,
some_int: u32,
data: []const i32,
pub fn serialize_to(
self: @This(),
writer: *std.Io.Writer,
) !void
{
try writer.writeAll(&std.mem.toBytes(self.some_float));
try writer.writeInt(
@TypeOf(self.some_int),
self.some_int,
ENDIAN,
);
try writer.writeInt(
usize,
self.data.len,
ENDIAN,
);
try writer.writeSliceEndian(i32, self.data, ENDIAN);
}
pub fn deserialize_from(
allocator: std.mem.Allocator,
reader: *std.Io.Reader,
) !@This()
{
const f = std.mem.bytesToValue(
f32,
try reader.take(
@sizeOf(f32)
)
);
const i = try reader.takeInt(
u32,
ENDIAN,
);
// array from end
const size = try reader.takeInt(
usize,
ENDIAN,
);
const data = try allocator.alloc(i32, size);
try reader.readSliceEndian(i32, data,ENDIAN);
return .{
.some_float = f,
.some_int = i,
.data = data,
};
}
};
const HEADER_KEY = "TEST_DATA_HEADER\n";
const HEADER_CONSTANT_INT = 123456;
const HEADER_CONSTANT_F:f32 = 0.123456;
const TAIL_KEY = "\nGoodbye and good test!\n";
/// takes a writer and writes some stuff to the writer, returns bytes written
pub fn example_write_a_header(
writer: *std.Io.Writer,
) !void
{
// starter string
try writer.writeAll(HEADER_KEY);
// write the constant in two different endians
try writer.writeInt(i64, HEADER_CONSTANT_INT, .big);
try writer.writeInt(i64, HEADER_CONSTANT_INT, .little);
// I don't see a `writeFloat`, so using `std.mem.asBytes` to write those
try writer.writeAll(&std.mem.toBytes(HEADER_CONSTANT_F));
// testing round trip through bytes
try std.testing.expectEqual(
HEADER_CONSTANT_F,
std.mem.bytesToValue(
@TypeOf(HEADER_CONSTANT_F),
&std.mem.toBytes(HEADER_CONSTANT_F),
),
);
try writer.flush();
}
/// example function to read the header that was written
pub fn example_read_header(
reader: *std.Io.Reader,
) !void
{
var top_buf: [HEADER_KEY.len]u8 = undefined;
try reader.readSliceAll(&top_buf);
std.debug.assert(std.mem.eql(u8, &top_buf, HEADER_KEY));
std.debug.print("read: {s}\n", .{ top_buf });
{
const num = try reader.takeInt(i64, .big);
try std.testing.expectEqual(
HEADER_CONSTANT_INT,
num,
);
std.debug.print("read int (big end): {d}\n", .{ num });
}
{
const num = try reader.takeInt(i64, .little);
try std.testing.expectEqual(
HEADER_CONSTANT_INT,
num,
);
std.debug.print("read int (little end): {d}\n", .{ num });
}
{
const read_f = try reader.take(@sizeOf(@TypeOf(HEADER_CONSTANT_F)));
const val = std.mem.bytesToValue(
@TypeOf(HEADER_CONSTANT_F),
read_f,
);
std.debug.print(
"read float: {d} (from buf of length: {d})\n",
.{ val, read_f.len }
);
try std.testing.expectEqual(HEADER_CONSTANT_F, val);
}
}
test "writer + reader interface example"
{
const f_path = "/var/tmp/example_output.dat";
{
var f_out = try std.fs.cwd().createFile(
f_path,
.{},
);
defer f_out.close();
// write a header
var write_buf:[1024]u8 = undefined;
var f_writer = f_out.writer(&write_buf);
try example_write_a_header(&f_writer.interface);
// write a packed struct - little endian
{
const test_struct = ExamplePacked{
.some_float = 1.345,
.some_int = 1345,
};
try f_writer.interface.writeStruct(
test_struct,
.little,
);
}
try f_writer.interface.flush();
// write a non packed struct
{
const test_struct = ExampleNonPacked {
.some_float = 1.11,
.some_int = 1,
.data = &.{ 0, 1, 2, 3, 4, 5, 6 },
};
try test_struct.serialize_to(&f_writer.interface);
}
// write a packed struct - big endian
{
const test_struct = ExamplePacked{
.some_float = -3.14159,
.some_int = 2025,
};
try f_writer.interface.writeStruct(
test_struct,
.big,
);
}
try f_writer.interface.writeAll(TAIL_KEY);
try f_writer.interface.flush();
std.debug.print("wrote {d} bytes\n", .{ f_writer.pos });
}
// read it all back in
{
var f_in = try std.fs.cwd().openFile(
f_path,
.{},
);
defer f_in.close();
var read_buf:[1024]u8 = undefined;
var f_reader = f_in.reader(&read_buf);
try example_read_header(&f_reader.interface);
{
const s = try f_reader.interface.takeStruct(
ExamplePacked,
ENDIAN,
);
try std.testing.expectEqual(1345, s.some_int);
}
// non-packed struct
{
const s = try ExampleNonPacked.deserialize_from(
std.testing.allocator,
&f_reader.interface
);
defer std.testing.allocator.free(s.data);
try std.testing.expectEqualSlices(
i32,
&.{ 0, 1, 2, 3, 4, 5, 6 },
s.data,
);
}
{
const s = try f_reader.interface.takeStruct(
ExamplePacked,
.big,
);
try std.testing.expectEqual(2025, s.some_int);
}
var tail:[TAIL_KEY.len]u8 = undefined;
try f_reader.interface.readSliceAll(&tail);
std.debug.print("read: {s}\n",.{tail});
try std.testing.expectEqualStrings(TAIL_KEY, &tail);
std.debug.print("read {d} bytes\n", .{ f_reader.pos });
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment