I have a pattern where I have a stream which produces length-prefixed data. The parsing is rather complicated, so I use a LimitedReader and read until EndOfStream to know when I should stop parsing.
How can I accomplish similar behavior in Zig 0.15.1?
Here is the (admitidly complicated) code snippet:
pub fn readPDOBitLengths(
port: *Port,
station_address: u16,
direction: pdi.Direction,
recv_timeout_us: u32,
eeprom_timeout_us: u32,
) !u32 {
const catagory = try findCatagoryFP(
port,
station_address,
switch (direction) {
.input => .TXPDO,
.output => .RXPDO,
},
recv_timeout_us,
eeprom_timeout_us,
) orelse return 0;
// entries are 8 bytes, pdo header is 8 bytes, so
// this should be a multiple of eight.
if (catagory.byte_length % 8 != 0) return error.InvalidSII;
var stream = SIIStream.init(
port,
station_address,
catagory.word_address,
recv_timeout_us,
eeprom_timeout_us,
&.{},
);
// ^^^ new zig 0.15.1 reader is at &stream.reader
var limited_reader = std.io.limitedReader(stream.reader(), catagory.byte_length);
const reader = limited_reader.reader();
const State = enum {
pdo_header,
entries,
entries_skip,
};
var pdo_header: PDO.Header = undefined;
var entries_remaining: u8 = 0;
var total_bit_length: u32 = 0;
state: switch (State.pdo_header) {
.pdo_header => {
assert(entries_remaining == 0);
pdo_header = wire.packFromECatReader(PDO.Header, reader) catch |err| switch (err) {
error.EndOfStream => return total_bit_length, // <<<<<<<<<-----------------------EndOfStream here!
error.LinkError => return error.LinkError,
error.Timeout => return error.Timeout,
};
if (pdo_header.n_entries > PDO.max_entries) return error.InvalidSII;
entries_remaining = pdo_header.n_entries;
if (pdo_header.isUsed()) continue :state .entries else continue :state .entries_skip;
},
.entries => {
if (entries_remaining == 0) continue :state .pdo_header;
const entry = wire.packFromECatReader(PDO.Entry, reader) catch return error.InvalidSII;
entries_remaining -= 1;
total_bit_length += entry.bit_length;
continue :state .entries;
},
.entries_skip => {
if (entries_remaining == 0) continue :state .pdo_header;
_ = wire.packFromECatReader(PDO.Entry, reader) catch return error.InvalidSII;
entries_remaining -= 1;
continue :state .entries_skip;
},
}
}