I’m trying to implement something that adheres to the reader interface so I can use its many conveniences.
I have a function that will return 4 bytes or an error (readSII4ByteFP
) and I would like to wrap it in a Reader.
I think I am close but I am having trouble. I have been looking at std.io.fixedBufferStream
as an example.
pub const SIIStream = struct {
port: *Port,
station_address: u16,
retries: u32,
recv_timeout_us: u32,
eeprom_timeout_us: u32,
eeprom_address: u32, // WORD (2-byte) address
last_four_bytes: [4]u8 = .{ 0, 0, 0, 0 },
remainder: u2 = 0,
pub fn init(
port: *Port,
station_address: u16,
eeprom_address: u16,
retries: u32,
recv_timeout_us: u32,
eeprom_timeout_us: u32,
) SIIStream {
return SIIStream{
.port = port,
.station_address = station_address,
.eeprom_address = eeprom_address,
.retries = retries,
.recv_timeout_us = recv_timeout_us,
.eeprom_timeout_us = eeprom_timeout_us,
};
}
const ReadError = error{};
pub fn reader(self: *SIIStream) std.io.Reader {
return std.io.AnyReader(@This(), @This().ReadError, read);
}
fn read(self: *SIIStream, buf: []u8) !usize {
if (self.remainder == 0) {
self.last_four_bytes = try readSII4ByteFP(
self.port,
self.station_address,
self.eeprom_address, // eeprom address is WORD address
self.retries,
self.recv_timeout_us,
self.eeprom_timeout_us,
);
self.eeprom_address += 2;
}
if (buf.len >= 4) {
@memcpy(buf[0..4], self.last_four_bytes);
self.remainder = 0;
return 4;
} else {
@memcpy(buf, self.last_four_bytes[0..buf.len]);
self.remainder -%= @as(u2, @intCast(buf.len));
return buf.len;
}
}
};
And do I need to handle slices with zero length?