With Zig 0.14 I used a struct to wrap around an existing writer to treat consecutive newlines as only one newline and perform a few other minor transformations. I’m porting this into Zig 0.15 and I’ve come up with the following code. It works but I’m wondering if this is a good pattern or if others have betters ideas for accomplishing the same thing:
const NewlineFilterWriterWrapper = struct {
writer: *std.Io.Writer,
interface: std.Io.Writer,
const Self = @This();
fn drain(w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize {
const self: *NewlineFilterWriterWrapper = @fieldParentPtr("interface", w);
// Add custom logic here, update data if necessary
// use self.writer.vtable.drain(...) to forward the writes
}
fn sendFile(w: *std.Io.Writer, reader: *std.Io.Reader, limit: std.Io.Limit) !usize {
const self: *NewlineFilterWriterWrapper = @fieldParentPtr("interface", w);
return self.writer.vtable.sendFile(self.writer, reader, limit);
}
fn flush(w: *std.Io.Writer) error{WriteFailed}!void {
const self: *NewlineFilterWriterWrapper = @fieldParentPtr("interface", w);
return self.writer.vtable.flush(self.writer);
}
fn rebase(w: *std.Io.Writer, preserve: usize, capacity: usize) error{WriteFailed}!void {
const self: *NewlineFilterWriterWrapper = @fieldParentPtr("interface", w);
return self.writer.vtable.rebase(self.writer, preserve, capacity);
}
fn init(writer: *std.Io.Writer) NewlineFilterWriterWrapper {
return .{
.writer = writer,
.interface = .{
.buffer = writer.buffer,
.end = writer.end,
.vtable = &.{
.drain = drain,
.sendFile = sendFile,
.rebase = rebase,
.flush = flush,
},
},
};
}
};