How to pass write stream from std.json correctly?

I want to implement jsonStringify fn on both Location and Person so they can be called separately also I would really like keep using write stream from std.json.writeStream so I can use beginObject beginArray and so on. I tried to solve this problem with AI/LLMs help but it seems lost and/or it keep changing the api by writing strings directly. Any ideas?

Error:

panic: reached unreachable code
lib/std/json/stringify.zig:282:43: 0x1043314e3 in endObject (zig-curl)
                .the_beginning, .colon => unreachable,
                                          ^
/private/tmp/json-test/src/main.zig:29:25: 0x10433184f in jsonStringify__anon_1610 (json-test)
        try ws.endObject();
                        ^
/private/tmp/json-test/src/main.zig:45:29: 0x104331bef in main (json-test)
    try person.jsonStringify(.{ .whitespace = .indent_2 }, out.writer());
                            ^
lib/std/start.zig:532:37: 0x104332267 in main (json-test)
            const result = root.main() catch |err| {
const std = @import("std");

pub const Location = struct {
    lat: f32,
    lon: f32,

    pub fn jsonStringify(self: *const Location, options: std.json.StringifyOptions, writer: anytype) !void {
        var ws = std.json.writeStream(writer, options);
        try ws.beginObject();
        try ws.objectField("lat");
        try ws.write(self.lat);
        try ws.objectField("lon");
        try ws.write(self.lon);
        try ws.endObject();
    }
};

pub const Person = struct {
    name: []const u8,
    location: Location,

    pub fn jsonStringify(self: *const Person, options: std.json.StringifyOptions, writer: anytype) !void {
        var ws = std.json.writeStream(writer, options);
        try ws.beginObject();
        try ws.objectField("name");
        try ws.write(self.name);
        try ws.objectField("location");
        try self.location.jsonStringify(options, writer);
        try ws.endObject();
    }
};

pub fn main() !void {
    var person = Person{
        .name = "Zig",
        .location = Location{
            .lat = 12.34,
            .lon = 56.78,
        },
    };

    var out = std.ArrayList(u8).init(std.heap.page_allocator);
    defer out.deinit();

    try person.jsonStringify(.{ .whitespace = .indent_2 }, out.writer());

    std.debug.print("\n{s}\n", .{out.items});
}

I believe the problem is the creation of multiple std.json.WriteStream in each of your jsonStringify functions.

The JSON module has support for structs that define a jsonStringify function, but you need the right signature:

EDIT: Also note that to start the stringification process, it is recommended to use std.json.stringify.

const std = @import("std");

pub const Location = struct {
    lat: f32,
    lon: f32,

    pub fn jsonStringify(self: Location, ws: anytype) !void {
        try ws.beginObject();
        try ws.objectField("lat");
        try ws.write(self.lat);
        try ws.objectField("lon");
        try ws.write(self.lon);
        try ws.endObject();
    }
};

pub const Person = struct {
    name: []const u8,
    location: Location,

    pub fn jsonStringify(self: Person, ws: anytype) !void {
        try ws.beginObject();
        try ws.objectField("name");
        try ws.write(self.name);
        try ws.objectField("location");
        try ws.write(self.location);
        try ws.endObject();
    }
};

pub fn main() !void {
    const person = Person{
        .name = "Zig",
        .location = Location{
            .lat = 12.34,
            .lon = 56.78,
        },
    };

    var out = std.ArrayList(u8).init(std.heap.page_allocator);
    defer out.deinit();

    try std.json.stringify(person, .{ .whitespace = .indent_2 }, out.writer());

    std.debug.print("\n{s}\n", .{out.items});
}
$ zig run ./test.zig

{
  "name": "Zig",
  "location": {
    "lat": 1.234000015258789e1,
    "lon": 5.6779998779296875e1
  }
}
2 Likes

The JSON module has support for structs that define a jsonStringify function, but you need the right signature:

Reading the stringify.zig code made things much clearer, thank you!

1 Like