// benchmark std.json vs aether

const bigdata = @embedFile("10mb.json");
const std = @import("std");

fn aetherbenchAux(allocator: std.mem.Allocator) !void {
    const aether = @import("aether");

    const Tokenizer = aether.Tokenizer;
    const Language = aether.Language;

    var tokenizer: Tokenizer = try .init(allocator, bigdata);
    errdefer tokenizer.deinit(allocator);

    var self = try allocator.create(Language);
    self.* = Language.init;
    defer allocator.destroy(self);
    defer self.deinit(allocator);

    const idx: usize = try self.parse(allocator, &tokenizer);

    var root = try self.getValue(allocator, idx);
    defer root.deinit(allocator);

    try std.testing.expect(root == .object);
    //std.debug.print("{}\n", .{root});
}

fn stdjsonbenchAux(allocator: std.mem.Allocator) !void {
    const json = std.json;

    const root = try json.parseFromSliceLeaky(json.Value, allocator, bigdata, .{
        .allocate = .alloc_always,
        .duplicate_field_behavior = .@"error",
        .max_value_len = 4096,
        .ignore_unknown_fields = true,
    });

    try std.testing.expect(root == .object);
    //std.debug.print("{}\n", .{root});
}

pub fn aetherbench(allocator: std.mem.Allocator) void {
    aetherbenchAux(allocator) catch @panic("aetherbench failed");
}
pub fn stdjsonbench(allocator: std.mem.Allocator) void {
    stdjsonbenchAux(allocator) catch @panic("aetherbench failed");
}

pub fn main() !void {
    const zbench = @import("zbench");
    const stdout = std.io.getStdOut().writer();
    var gpa: std.heap.GeneralPurposeAllocator(.{}) = .{};
    const allocator = gpa.allocator();

    var bench = zbench.Benchmark.init(allocator, .{
        .iterations = 2,
    });
    defer {
        bench.deinit();
        const deinit_status = gpa.deinit();
        if (deinit_status == .leak)
            std.debug.panic("Memory leak detected", .{});
    }

    try bench.add("aether", &aetherbench, .{
        .track_allocations = true,
    });
    try bench.add("std.json", &stdjsonbench, .{
        .track_allocations = true,
    });

    try stdout.writeByte('\n');
    try bench.run(stdout);

    try stdout.writeAll("[");
    var iter = try bench.iterator();
    var i: usize = 0;
    while (try iter.next()) |step| switch (step) {
        .progress => |_| {},
        .result => |x| {
            defer x.deinit();
            defer i += 1;
            if (0 < i) try stdout.writeAll(", ");
            try x.writeJSON(gpa.allocator(), stdout);
        },
    };
    try stdout.writeAll("]\n");
}
