mirror of
https://codeberg.org/fairyglade/ly.git
synced 2026-08-19 12:04:19 +02:00
137 lines
4.7 KiB
Zig
137 lines
4.7 KiB
Zig
const std = @import("std");
|
|
|
|
pub const ini = @import("zigini");
|
|
pub const zlua = @import("zlua");
|
|
pub const Lua = zlua.Lua;
|
|
|
|
pub const interop = @import("interop.zig");
|
|
pub const UidRange = @import("UidRange.zig");
|
|
pub const LogFile = @import("LogFile.zig");
|
|
pub const SharedError = @import("SharedError.zig");
|
|
|
|
pub fn IniParser(comptime Struct: type) type {
|
|
return struct {
|
|
const Self = @This();
|
|
const temporary_allocator = std.heap.page_allocator;
|
|
|
|
pub const Error = struct {
|
|
type_name: []const u8,
|
|
key: []const u8,
|
|
value: []const u8,
|
|
error_name: []const u8,
|
|
};
|
|
pub var global_errors: std.ArrayList(Error) = .empty;
|
|
|
|
ini_struct: ini.Ini(Struct),
|
|
structure: Struct,
|
|
maybe_load_error: ?anyerror,
|
|
errors: std.ArrayList(Error),
|
|
|
|
pub fn init(
|
|
allocator: std.mem.Allocator,
|
|
io: std.Io,
|
|
path: []const u8,
|
|
field_handler: ?fn (allocator: std.mem.Allocator, field: ini.IniField) ?ini.IniField,
|
|
) !Self {
|
|
var ini_struct = ini.Ini(Struct).init(allocator);
|
|
errdefer ini_struct.deinit();
|
|
|
|
var maybe_load_error: ?anyerror = null;
|
|
|
|
const structure = ini_struct.readFileToStruct(io, path, .{
|
|
.fieldHandler = field_handler,
|
|
.errorHandler = errorHandler,
|
|
.comment_characters = "#",
|
|
}) catch |err| load_error: {
|
|
maybe_load_error = err;
|
|
break :load_error Struct{};
|
|
};
|
|
|
|
return .{
|
|
.ini_struct = ini_struct,
|
|
.structure = structure,
|
|
.maybe_load_error = maybe_load_error,
|
|
.errors = global_errors,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *Self) void {
|
|
self.ini_struct.deinit();
|
|
|
|
for (0..global_errors.items.len) |i| {
|
|
const err = global_errors.items[i];
|
|
temporary_allocator.free(err.type_name);
|
|
temporary_allocator.free(err.key);
|
|
temporary_allocator.free(err.value);
|
|
}
|
|
|
|
global_errors.deinit(temporary_allocator);
|
|
}
|
|
|
|
fn errorHandler(type_name: []const u8, key: []const u8, value: []const u8, err: anyerror) void {
|
|
global_errors.append(temporary_allocator, .{
|
|
.type_name = temporary_allocator.dupe(u8, type_name) catch return,
|
|
.key = temporary_allocator.dupe(u8, key) catch return,
|
|
.value = temporary_allocator.dupe(u8, value) catch return,
|
|
.error_name = @errorName(err),
|
|
}) catch return;
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn LuaParser(comptime Struct: type) type {
|
|
return struct {
|
|
const Self = @This();
|
|
|
|
structure: Struct,
|
|
|
|
pub fn init(
|
|
allocator: std.mem.Allocator,
|
|
io: std.Io,
|
|
path: []const u8,
|
|
) !Self {
|
|
var lua: Lua = try .init(allocator);
|
|
defer lua.deinit();
|
|
|
|
lua.openLibs();
|
|
|
|
// convert to sentinel terminated slice
|
|
const spath: [:0]const u8 = try allocator.dupeSentinel(u8, path, 0);
|
|
lua.doFile(spath) catch {
|
|
const error_str = lua.toString(-1) catch unreachable;
|
|
const lua_str = try allocator.dupeSentinel(u8, error_str, 0);
|
|
_ = lua_str; // TODO add error logging
|
|
};
|
|
var data: Struct = .{};
|
|
switch (@typeInfo(Struct)) {
|
|
.@"struct" => |struc| {
|
|
inline for (struc.fields) |field| {
|
|
try setField(allocator, lua, field, &data);
|
|
}
|
|
},
|
|
else => @compileError("Expected a struct."),
|
|
}
|
|
|
|
return data;
|
|
}
|
|
pub fn setField(allocator: std.mem.Allocator, lua: *Lua, comptime field: std.builtin.Type.StructField, data: *Struct) !void {
|
|
try lua.getGlobal("ly");
|
|
defer lua.pop(1); // pop ly table
|
|
switch (@typeInfo(field.type)) {
|
|
.int => {
|
|
_ = lua.getField(-1, field.name);
|
|
const value = try lua.toInteger(-1);
|
|
lua.pop(1);
|
|
@field(data, field.name) = @intCast(@as(field.type, @truncate(value)));
|
|
},
|
|
.float => {
|
|
_ = lua.getField(-1, field.name);
|
|
const value = try lua.toNumber(-1);
|
|
lua.pop(1);
|
|
@field(data, field.name) = @floatCast(@as(field.type, value));
|
|
},
|
|
else => @compileError("unimplemented!"),
|
|
}
|
|
}
|
|
};
|
|
}
|