const std = @import("std"); const toml = @import("toml"); const Allocator = std.mem.Allocator; const Io = std.Io; const tvalue = toml.value_mod; pub const ReadError = Allocator.Error || Io.Cancelable || error{ FileNotFound, ReadFailed }; pub fn readFileAlloc(allocator: Allocator, io: Io, path: []const u8) ReadError![]u8 { const file = Io.Dir.cwd().openFile(io, path, .{ .mode = .read_only }) catch |err| switch (err) { error.FileNotFound => return error.FileNotFound, error.Canceled => return error.Canceled, else => return error.ReadFailed, }; defer file.close(io); const len = file.length(io) catch return error.ReadFailed; const bytes = try allocator.alloc(u8, @intCast(len)); errdefer allocator.free(bytes); _ = file.readPositionalAll(io, bytes, 0) catch |err| switch (err) { error.Canceled => return error.Canceled, else => return error.ReadFailed, }; return bytes; } pub fn mergeTable(alloc: Allocator, dst: *toml.Value, src: *const toml.Value) Allocator.Error!void { std.debug.assert(dst.* == .table); if (src.* != .table) return; var it = toml.tableIterator(src); while (it.next()) |entry| { const existing = dst.get(entry.key); if (existing != null and existing.?.* == .table and entry.value.* == .table) { try mergeTable(alloc, @constCast(existing.?), entry.value); } else { const copy = try cloneValue(alloc, entry.value); const key_copy = try alloc.dupe(u8, entry.key); try tvalue.tableSet(alloc, dst, key_copy, copy); } } } fn cloneValue(alloc: Allocator, src: *const toml.Value) Allocator.Error!*toml.Value { const out = try alloc.create(toml.Value); switch (src.*) { .table => { out.* = .{ .table = .{} }; var it = toml.tableIterator(src); while (it.next()) |entry| { const child = try cloneValue(alloc, entry.value); const key_copy = try alloc.dupe(u8, entry.key); try tvalue.tableSet(alloc, out, key_copy, child); } }, .array => |*a| { out.* = .{ .array = .{} }; for (a.items.items) |*item| { const child = try cloneValue(alloc, item); try tvalue.arrayAppend(alloc, out, child.*); } }, .string => |s| out.* = .{ .string = try alloc.dupe(u8, s) }, else => out.* = src.*, } return out; }