lib/choir/src/backends/artifact/model/option.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const Allocator = std.mem.Allocator;
3 const artifact = @import("root.zig");
4 const slice = artifact.slice;
5
6 pub const OptionValueTag = enum(u8) {
7 flag = 1,
8 signed = 2,
9 unsigned = 3,
10 text = 4,
11 bytes = 5,
12 };
13
14 pub const OptionValue = union(OptionValueTag) {
15 flag: bool,
16 signed: i64,
17 unsigned: u64,
18 text: []const u8,
19 bytes: []const u8,
20
21 pub fn dupe(self: OptionValue, allocator: Allocator) Allocator.Error!OptionValue {
22 return switch (self) {
23 .flag => |value| .{ .flag = value },
24 .signed => |value| .{ .signed = value },
25 .unsigned => |value| .{ .unsigned = value },
26 .text => |value| .{ .text = try slice.dupe(allocator, value) },
27 .bytes => |value| .{ .bytes = try slice.dupe(allocator, value) },
28 };
29 }
30
31 pub fn deinit(self: OptionValue, allocator: Allocator) void {
32 switch (self) {
33 .text => |value| slice.free(allocator, value),
34 .bytes => |value| slice.free(allocator, value),
35 else => {},
36 }
37 }
38
39 pub fn eql(self: OptionValue, other: OptionValue) bool {
40 if (std.meta.activeTag(self) != std.meta.activeTag(other)) return false;
41 return switch (self) {
42 .flag => |value| value == other.flag,
43 .signed => |value| value == other.signed,
44 .unsigned => |value| value == other.unsigned,
45 .text => |value| std.mem.eql(u8, value, other.text),
46 .bytes => |value| std.mem.eql(u8, value, other.bytes),
47 };
48 }
49 };
50
51 pub const BuildOption = struct {
52 key: []const u8,
53 value: OptionValue,
54
55 pub fn dupe(self: BuildOption, allocator: Allocator) Allocator.Error!BuildOption {
56 const key = try slice.dupe(allocator, self.key);
57 errdefer slice.free(allocator, key);
58 return .{ .key = key, .value = try self.value.dupe(allocator) };
59 }
60
61 pub fn deinit(self: BuildOption, allocator: Allocator) void {
62 slice.free(allocator, self.key);
63 self.value.deinit(allocator);
64 }
65
66 pub fn eql(self: BuildOption, other: BuildOption) bool {
67 return std.mem.eql(u8, self.key, other.key) and self.value.eql(other.value);
68 }
69 };
70
71 pub const Options = struct {
72 allocator: Allocator,
73 values: std.ArrayListUnmanaged(BuildOption) = .empty,
74
75 pub fn init(allocator: Allocator) Options {
76 return .{ .allocator = allocator };
77 }
78
79 pub fn add(self: *Options, option: BuildOption) Allocator.Error!void {
80 try self.values.ensureTotalCapacity(self.allocator, self.values.items.len + 1);
81 const owned = try option.dupe(self.allocator);
82 self.values.appendAssumeCapacity(owned);
83 }
84
85 pub fn cloneInto(self: Options, target: *Options) Allocator.Error!void {
86 for (self.values.items) |option| try target.add(option);
87 }
88
89 pub fn deinit(self: *Options) void {
90 for (self.values.items) |option| option.deinit(self.allocator);
91 self.values.deinit(self.allocator);
92 self.* = undefined;
93 }
94
95 pub fn eql(self: Options, other: Options) bool {
96 if (self.values.items.len != other.values.items.len) return false;
97 for (self.values.items, other.values.items) |left, right| {
98 if (!left.eql(right)) return false;
99 }
100 return true;
101 }
102 };