summaryrefslogtreecommitdiff
path: root/src/toml_layer.zig
blob: a2c194216c263ff9c3fc065a01355914e6ff31f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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;
}