Using JSON with zig to save/load data

I wanted to be able to emit JSON from my cidr-rdns tool to make it searchable and includable as a data source for many OSINT tools. This was relatively easy using the Stringify function in zig and using a file writer interface.

var global_entries: std.ArrayList(Entry) = undefined;

fn toFile(io: std.Io, fileName: []const u8) !void {
    var file = try std.Io.Dir.cwd().createFile(io, fileName, .{});
    defer file.close(io);

    var buffer: [4096]u8 = undefined;
    var file_writer: std.Io.File.Writer = file.writer(io, &buffer);
    const writer = &file_writer.interface;

    std.log.info("Opened {s} for writing.", .{fileName});

    var stringify: std.json.Stringify = .{
        .writer = writer,
    };

    for (global_entries.items) |entry| {
        try stringify.write(.{ .ip_str = entry.ip_str, .hostname = entry.hostname });
        try writer.writeByte('\n');
    }
    try writer.flush();
    std.log.info("Finished writting to file.", .{});
}

The method to load a JSON string into a struct from a file is nearly identical to using ZON. For whatever reason, the JSON parser doesn't require a null terminated string, as that is one of life's many mysteries. Using a FixedBufferAllocator on small JSON entries would be optimal here.

const Entry = struct {
    ip_str: []const u8,
    hostname: []const u8,
};

fn readFromFile(io: std.Io, allocator: std.mem.Allocator, fileName: []const u8) ![]Entry {
    var ret = std.ArrayList(Entry) = .empty;
    errdefer ret.deinit();

    var buffer: [4096]u8 = undefined;
    var file = try std.Io.Dir.cwd().openFile(io, fileName, .{ .mode = .read_only });
    defer file.close(io);

    var frb = file.reader(io, &buffer);
    var reader = &frb.interface;

    while (reader.takeDelimiterInclusive(deliminator)) |line| { // Using a FixedBufferAllocator would be faster and more effective here.
        const parsed = try std.json.parseFromSlice(Entry, allocator, line, null, .{ .free_on_error = true });
        defer allocator.free(parsed);
        try ret.append(allocator, parsed);
    }

    return ret.toOwnedSlice();
}

That concludes this exciting adventure of coding in zig.