Writergate fix for tinyvg?

I’m trying to make Writergate fixes to tinyvg and I’m absolutely stuck on this code from binding.zig:

const CWriter = std.io.Writer(*const c.tinyvg_OutStream, CError, writeCStream);

fn writeCStream(stream: *const c.tinyvg_OutStream, data: []const u8) CError!usize {
    var written: usize = 0;

    try errToZig(stream.write.?(stream.context, data.ptr, data.len, &written));

    return written;
}

What do I need to do to make that Writergate compliant?

Thanks.

That looks like a low level wrapper of the c function.

You would call that from your writer implementation.

On further thought, you don’t seem to have done anything regarding the new writer interface yet, so here’s an explanation.

The new reader/writer interfaces are intrusive interfaces, meaning they are intended to be used as fields of the implementing type, the interface functions you implement and pass the interface field when you create your type will be given a pointer to the reader/writer. The implemented functions access the implementation state using @fieldParentPtr.

The above means you can’t copy the interface field out of the implementation type, it must be referenced by a pointer. You also can’t move the implementation while a pointer to the interface is being used, but that’s not specific to intrusive interfaces.

The new interfaces have their own state of a buffer and indexes for where in the buffer is actual data or unused space, which the implementations are expected to access and modify.

Look at std.Io.Writer.Allocating or std.fs.File.Writer for examples.

Here is a video that explains it well Video: Zig's new Reader and Writer interfaces (std.Io, 0.15.1)

Well, I’m not really the owner of tinyvg, so heavily intrusive changes aren’t likely to get accepted.

I was really hoping for something contained. If it’s going to be that intrusive, I guess I’ll just need to file a bug and hope that the maintainer will update. :frowning:

what, no intrusive is refering to the kind of interface, not the changes you need to make.

which will be intrusive, but thats cause its a change in a fundamental type for streaming data, its unavoidable.

Sorry for the confusion.

I looked at what would be required to ripple the Writergate changes through the TinyVG codebase, and they appear to be non-trivial and extensive.

Okay, I traced out the interactions and I managed to push the shims together into a different function which minimizes the disruption.

At this point I’m stymied, but I think I have all the puzzle pieces and just don’t know how to assemble them. Any help would be appreciated.

The key function where the two worlds collide:

fn renderSvg(data: []const u8, stream: *const c.tinyvg_OutStream) !void {
    var temp_mem = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer temp_mem.deinit();

    const writer: std.Io.Writer = ZZZZZZ;  // FIXME: What do I put here?

    try tvg.svg.renderBinary(&writer, temp_mem.allocator(), data);

    writer.flush();
}

The functions operating on external stuff:

pub const struct_tinyvg_OutStream = extern struct {
    context: ?*anyopaque,
    write: ?*const fn (?*anyopaque, [*c]const u8, usize, [*c]usize) callconv(.c) enum_tinyvg_Error,
};

fn writeCStream(stream: *const c.tinyvg_OutStream, data: []const u8) CError!usize {
    var written: usize = 0;

    try errToZig(stream.write.?(stream.context, data.ptr, data.len, &written));

    return written;
}

Thanks.

const writer = //create an instance of your writer implementation
// assumes you call the interface field `interface`
try tvg.svg.renderBinary(&writer.interface, temp_mem.allocator(), data);

remember std.Io.Writer should always be behind a pointer (except as the field of the implementation).

It’s that “create an instance of your writer implementation” that has me stumped.

I figure I’m supposed to create a writer that somehow uses the stream.context and stream.write functions, but it’s not clear at all how I’m supposed to assemble that.

I guess I’ll go poke at the std.fs.File stuff and see if I get any inspiration.