aboutsummaryrefslogtreecommitdiffstats
path: root/src/config.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.zig')
-rw-r--r--src/config.zig339
1 files changed, 339 insertions, 0 deletions
diff --git a/src/config.zig b/src/config.zig
new file mode 100644
index 0000000..8d296dc
--- /dev/null
+++ b/src/config.zig
@@ -0,0 +1,339 @@
+const c = @import("c.zig");
+const fs = @import("std").fs;
+const std = @import("std");
+const debug = @import("std").debug;
+
+pub const OutputType = enum {
+ window,
+};
+
+pub const OutputConfig = struct {
+ type: OutputType,
+ width: i32,
+ height: i32,
+ fullscreen: bool, // only for `Window`
+};
+
+pub const ParameterConfig = struct {
+ name: []const u8,
+ type: []const u8,
+};
+
+const defaultOutput = OutputConfig{
+ .type = OutputType.window,
+ .width = 800,
+ .height = 600,
+ .fullscreen = false,
+};
+
+pub const Config = struct {
+ width: i32,
+ height: i32,
+ outputs: []const OutputConfig,
+ fragment: []const u8,
+ parameters: []const ParameterConfig,
+ arena: std.heap.ArenaAllocator,
+
+ pub fn parse(filename: []const u8) !Config {
+ var parser: c.yaml_parser_t = undefined;
+ _ = c.yaml_parser_initialize(&parser);
+ defer c.yaml_parser_delete(&parser);
+
+ const file = try fs.cwd().openFile(filename, .{});
+ // c.yaml_parser_set_input_file(&parser, @as([*c]c.FILE, file.handle));
+ var buffer: [1024]u8 = undefined;
+ const len: usize = try file.read(buffer[0..]);
+ c.yaml_parser_set_input_string(&parser, &buffer[0], len);
+
+ var config: Config = .{
+ .width = 1920,
+ .height = 1080,
+ .outputs = ([_]OutputConfig{defaultOutput})[0..],
+ .fragment = "sphere.frag",
+ .parameters = ([0]ParameterConfig{})[0..],
+ .arena = std.heap.ArenaAllocator.init(std.heap.page_allocator),
+ };
+
+ try expectEvent(&parser, c.yaml_event_type_t.YAML_STREAM_START_EVENT);
+ try expectEvent(&parser, c.yaml_event_type_t.YAML_DOCUMENT_START_EVENT);
+ try expectEvent(&parser, c.yaml_event_type_t.YAML_MAPPING_START_EVENT);
+
+ while (true) {
+ var event: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(&parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ switch (event.type) {
+ c.yaml_event_type_t.YAML_MAPPING_END_EVENT => break,
+ c.yaml_event_type_t.YAML_SCALAR_EVENT => {
+ const data = event.data.scalar;
+ const key: []const u8 = data.value[0..data.length];
+
+ if (std.mem.eql(u8, key, "width")) {
+ config.width = try parseInt(&parser, i32);
+ } else if (std.mem.eql(u8, key, "height")) {
+ config.height = try parseInt(&parser, i32);
+ } else if (std.mem.eql(u8, key, "fragment")) {
+ config.fragment = try parseString(&parser, &config.arena.allocator);
+ } else if (std.mem.eql(u8, key, "outputs")) {
+ config.outputs = try parseOutputs(&parser, &config.arena.allocator);
+ } else if (std.mem.eql(u8, key, "parameters")) {
+ config.parameters = try parseParameters(&parser, &config.arena.allocator);
+ } else {
+ debug.warn("unknown key: '{}'\n", .{key});
+ try skipAny(&parser);
+ }
+ },
+ else => {
+ debug.warn("unexpected event: {}\n", .{event.type});
+ return error.InvalidConfiguration;
+ },
+ }
+ }
+
+ try expectEvent(&parser, c.yaml_event_type_t.YAML_DOCUMENT_END_EVENT);
+ try expectEvent(&parser, c.yaml_event_type_t.YAML_STREAM_END_EVENT);
+
+ return config;
+ }
+};
+
+fn expectEvent(parser: *c.yaml_parser_t, expectedType: c.yaml_event_type_t) !void {
+ var event: c.yaml_event_t = undefined;
+
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ if (event.type != expectedType) {
+ debug.warn("unexpected event: {}\n", .{event.type});
+ return error.InvalidConfiguration;
+ }
+}
+
+fn parseString(parser: *c.yaml_parser_t, allocator: *std.mem.Allocator) ![]const u8 {
+ var event: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ if (event.type != c.yaml_event_type_t.YAML_SCALAR_EVENT)
+ return error.InvalidType;
+
+ const data = event.data.scalar;
+ const value: []const u8 = data.value[0..data.length];
+ return try std.mem.dupe(allocator, u8, value);
+}
+
+fn parseInt(parser: *c.yaml_parser_t, comptime T: type) !T {
+ var event: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ if (event.type != c.yaml_event_type_t.YAML_SCALAR_EVENT)
+ return error.InvalidType;
+
+ const data = event.data.scalar;
+ const value: []const u8 = data.value[0..data.length];
+ return try std.fmt.parseInt(T, value, 10);
+}
+
+fn parseEnum(parser: *c.yaml_parser_t, comptime T: type) !T {
+ var event: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ if (event.type != c.yaml_event_type_t.YAML_SCALAR_EVENT)
+ return error.InvalidType;
+
+ const data = event.data.scalar;
+ const value: []const u8 = data.value[0..data.length];
+
+ inline for (@typeInfo(T).Enum.fields) |field| {
+ if (std.mem.eql(u8, value, field.name))
+ return @field(T, field.name);
+ }
+
+ return error.InvalidValue;
+}
+
+fn parseBool(parser: *c.yaml_parser_t) !bool {
+ var event: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ if (event.type != c.yaml_event_type_t.YAML_SCALAR_EVENT)
+ return error.InvalidType;
+
+ const data = event.data.scalar;
+ const value: []const u8 = data.value[0..data.length];
+
+ if (data.style != c.yaml_scalar_style_t.YAML_PLAIN_SCALAR_STYLE)
+ return false;
+ return std.mem.eql(u8, value, "true") or std.mem.eql(u8, value, "1");
+}
+
+fn parseOutputs(parser: *c.yaml_parser_t, allocator: *std.mem.Allocator) ![]OutputConfig {
+ try expectEvent(parser, c.yaml_event_type_t.YAML_SEQUENCE_START_EVENT);
+
+ var outputs = try allocator.alloc(OutputConfig, 1024);
+ var output_count: usize = 0;
+
+ while (true) {
+ var seqEvent: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(parser, &seqEvent) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&seqEvent);
+
+ switch (seqEvent.type) {
+ c.yaml_event_type_t.YAML_SEQUENCE_END_EVENT => break,
+ c.yaml_event_type_t.YAML_MAPPING_START_EVENT => {
+ var output = &outputs[output_count];
+ output.* = defaultOutput;
+
+ while (true) {
+ var event: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ switch (event.type) {
+ c.yaml_event_type_t.YAML_MAPPING_END_EVENT => break,
+ c.yaml_event_type_t.YAML_SCALAR_EVENT => {
+ const data = event.data.scalar;
+ const key: []const u8 = data.value[0..data.length];
+
+ if (std.mem.eql(u8, key, "type")) {
+ output.*.type = try parseEnum(parser, OutputType);
+ } else if (std.mem.eql(u8, key, "width")) {
+ output.*.width = try parseInt(parser, i32);
+ } else if (std.mem.eql(u8, key, "height")) {
+ output.*.height = try parseInt(parser, i32);
+ } else if (std.mem.eql(u8, key, "fullscreen")) {
+ output.*.fullscreen = try parseBool(parser);
+ } else {
+ debug.warn("unknown key: '{}'\n", .{key});
+ try skipAny(parser);
+ }
+ },
+ else => {
+ debug.warn("unexpected event: {}\n", .{event.type});
+ return error.InvalidConfiguration;
+ },
+ }
+ }
+
+ output_count += 1;
+ },
+ else => {
+ debug.warn("unexpected event: {}\n", .{seqEvent.type});
+ return error.InvalidConfiguration;
+ },
+ }
+ }
+
+ _ = allocator.realloc(outputs, output_count) catch 0;
+ return outputs[0..output_count];
+}
+
+fn parseParameters(parser: *c.yaml_parser_t, allocator: *std.mem.Allocator) ![]ParameterConfig {
+ try expectEvent(parser, c.yaml_event_type_t.YAML_SEQUENCE_START_EVENT);
+
+ var parameters = try allocator.alloc(ParameterConfig, 1024);
+ var param_count: usize = 0;
+
+ while (true) {
+ var seqEvent: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(parser, &seqEvent) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&seqEvent);
+
+ switch (seqEvent.type) {
+ c.yaml_event_type_t.YAML_SEQUENCE_END_EVENT => break,
+ c.yaml_event_type_t.YAML_MAPPING_START_EVENT => {
+ var param = &parameters[param_count];
+ var have_name = false;
+ var have_type = false;
+
+ while (true) {
+ var event: c.yaml_event_t = undefined;
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ switch (event.type) {
+ c.yaml_event_type_t.YAML_MAPPING_END_EVENT => break,
+ c.yaml_event_type_t.YAML_SCALAR_EVENT => {
+ const data = event.data.scalar;
+ const key: []const u8 = data.value[0..data.length];
+
+ if (std.mem.eql(u8, key, "name")) {
+ param.*.name = try parseString(parser, allocator);
+ have_name = true;
+ } else if (std.mem.eql(u8, key, "type")) {
+ param.*.type = try parseString(parser, allocator);
+ have_type = true;
+ } else {
+ debug.warn("unknown key: '{}'\n", .{key});
+ try skipAny(parser);
+ }
+ },
+ else => {
+ debug.warn("unexpected event: {}\n", .{event.type});
+ return error.InvalidConfiguration;
+ },
+ }
+ }
+
+ if (!(have_name and have_type)) {
+ debug.warn("name and type are mandatory for parameters.\n", .{});
+ return error.InvalidConfiguration;
+ }
+
+ param_count += 1;
+ },
+ else => {
+ debug.warn("unexpected event: {}\n", .{seqEvent.type});
+ return error.InvalidConfiguration;
+ },
+ }
+ }
+
+ _ = allocator.realloc(parameters, param_count) catch 0;
+ return parameters[0..param_count];
+}
+
+fn skipAny(parser: *c.yaml_parser_t) !void {
+ var event: c.yaml_event_t = undefined;
+ var depth: u32 = 0;
+ while (true) {
+ if (c.yaml_parser_parse(parser, &event) != 1)
+ return error.YAMLParserError;
+ defer c.yaml_event_delete(&event);
+
+ switch (event.type) {
+ c.yaml_event_type_t.YAML_SCALAR_EVENT => {
+ if (depth == 0)
+ break;
+ },
+
+ c.yaml_event_type_t.YAML_SEQUENCE_START_EVENT, c.yaml_event_type_t.YAML_MAPPING_START_EVENT => depth += 1,
+
+ c.yaml_event_type_t.YAML_SEQUENCE_END_EVENT, c.yaml_event_type_t.YAML_MAPPING_END_EVENT => {
+ depth -= 1;
+
+ if (depth == 0)
+ break;
+ },
+
+ else => {
+ debug.warn("unexpected event: {}\n", .{event.type});
+ return error.InvalidConfiguration;
+ },
+ }
+ }
+}