How to handle lots of print to stdout

I’m designing a VM that allows you to define your own print and printErr functions that we’ll be used to print to stdout and stderr, while provided a default implementation. It is meant to be used when embedded or in test mode for example.

The Config and default implementation are:

pub const Config = struct {
    printFn: *const fn ([]const u8) void = defaultPrint,
    ...
};

fn defaultPrint(text: []const u8) void {
    errdefer @panic("failed to write to stdout");

    var buf: [1024]u8 = undefined;
    var stdout_writer = std.fs.File.stdout().writer(&buf);
    const stdout = &stdout_writer.interface;

    try stdout.print("{s}\n", .{text});
    try stdout.flush();
}

When executing the print op code, I pop the last value on stack, print it to a buffer and then send it to the print function:

.print => {
    var wa = std.io.Writer.Allocating.init(self.allocator);
    var writer = &wa.writer;
    self.stack.pop().print(writer);
    self.state.config.printFn(writer.buffered());
},

This all process seems really not performant as a lot of stuff is done over and over but I’m not 100% used to new Io stuff.
What’s an elegant way to deal with that?

It looks like self.stack.pop().print(writer) already takes an Io.Writer as input.

What if Config had a writer that conforms to the Io.Writer interfaces and you pass that in. Internally, this implementation can call the printFn. You should only have to implement the drain function for this to work.

Then you would have:

.print => {
    self.stack.pop().print(self.state.config.writer);
},
2 Likes

Why not define it so that Config takes an *Io.Writer from the user?

pub const Config = struct {
    debug_writer: *Io.Writer,
    ..
};
1 Like

Dammit. Beat me by a minute. I think it’s definitely the most idiomatic way.

1 Like

I’ll have to check what does drain does but seems like a good idea. Thanks both for your answers!

2 Likes

Here is fixedDrain used in the FixedBuffer writer:
https://ziglang.org/documentation/0.15.1/std/#std.Io.Writer.fixedDrain

And drain from Writer.Allocating:
https://ziglang.org/documentation/0.15.1/std/#std.Io.Writer.Allocating.drain

That might be a good starting point.

1 Like