|
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 }); |
|
} |
|
} |