Skip to content

Commit d21df8f

Browse files
axdankrobbielyman
authored andcommitted
implement toTuple and others
1 parent 6b1fabe commit d21df8f

File tree

1 file changed

+129
-7
lines changed

1 file changed

+129
-7
lines changed

src/lib.zig

Lines changed: 129 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,34 @@ pub fn Parsed(comptime T: type) type {
585585
};
586586
}
587587

588+
const internals = [_][]const u8{ "toStruct", "toSlice", "toTuple", "toAnyInternal" };
589+
590+
// wrap over some internal functions of the Lua struct
591+
pub const Internals = blk: {
592+
const StructField = std.builtin.Type.StructField;
593+
var fields: [internals.len]StructField = undefined;
594+
for (internals, 0..) |entry, i| {
595+
const F = @field(Lua, entry);
596+
const T = @TypeOf(F);
597+
fields[i] = .{
598+
.name = @ptrCast(entry),
599+
.type = T,
600+
.default_value = &F,
601+
.is_comptime = false,
602+
.alignment = @alignOf(T),
603+
};
604+
}
605+
606+
const TT = @Type(.{ .@"struct" = .{
607+
.layout = .auto,
608+
.fields = &fields,
609+
.decls = &.{},
610+
.is_tuple = false,
611+
} });
612+
613+
break :blk TT{};
614+
};
615+
588616
/// A Zig wrapper around the Lua C API
589617
/// Represents a Lua state or thread and contains the entire state of the Lua interpreter
590618
pub const Lua = opaque {
@@ -4352,7 +4380,27 @@ pub const Lua = opaque {
43524380
/// Works with ints, floats, booleans, structs,
43534381
/// tagged unions, optionals, and strings
43544382
pub fn pushAny(lua: *Lua, value: anytype) !void {
4355-
switch (@typeInfo(@TypeOf(value))) {
4383+
const T = @TypeOf(value);
4384+
const type_info = @typeInfo(T);
4385+
4386+
if (type_info == .@"struct" or type_info == .@"union" or type_info == .@"enum") {
4387+
if (@hasDecl(T, "ziglua_pushAny")) {
4388+
const fnInfo = @typeInfo(@TypeOf(T.ziglua_pushAny)).@"fn";
4389+
switch (fnInfo.params.len) {
4390+
// fn(self, lua) -> void
4391+
2 => {
4392+
if (@typeInfo(fnInfo.return_type.?) == .error_union) {
4393+
return try value.ziglua_pushAny(lua);
4394+
} else {
4395+
return value.ziglua_pushAny(lua);
4396+
}
4397+
},
4398+
else => @compileError(@typeName(T) ++ ".ziglua_pushAny has invalid signature, required: fn(self: T, lua: *Lua) void"),
4399+
}
4400+
}
4401+
}
4402+
4403+
switch (type_info) {
43564404
.int, .comptime_int => {
43574405
lua.pushInteger(@intCast(value));
43584406
},
@@ -4407,10 +4455,18 @@ pub const Lua = opaque {
44074455
},
44084456
.@"struct" => |info| {
44094457
lua.createTable(0, 0);
4410-
inline for (info.fields) |field| {
4411-
try lua.pushAny(field.name);
4412-
try lua.pushAny(@field(value, field.name));
4413-
lua.setTable(-3);
4458+
if (info.is_tuple) {
4459+
inline for (0..info.fields.len) |i| {
4460+
try lua.pushAny(i + 1);
4461+
try lua.pushAny(value[i]);
4462+
lua.setTable(-3);
4463+
}
4464+
} else {
4465+
inline for (info.fields) |field| {
4466+
try lua.pushAny(field.name);
4467+
try lua.pushAny(@field(value, field.name));
4468+
lua.setTable(-3);
4469+
}
44144470
}
44154471
},
44164472
.@"union" => |info| {
@@ -4477,7 +4533,26 @@ pub const Lua = opaque {
44774533
}
44784534
}
44794535

4480-
switch (@typeInfo(T)) {
4536+
const type_info = @typeInfo(T);
4537+
4538+
if (type_info == .@"struct" or type_info == .@"union" or type_info == .@"enum") {
4539+
if (@hasDecl(T, "ziglua_toAny")) {
4540+
const fnInfo = @typeInfo(@TypeOf(T.ziglua_toAny)).@"fn";
4541+
switch (fnInfo.params.len) {
4542+
// fn(lua_state, alloc, allow_alloc, index) -> T
4543+
4 => {
4544+
if (@typeInfo(fnInfo.return_type.?) == .error_union) {
4545+
return try T.ziglua_toAny(lua, a, allow_alloc, index);
4546+
} else {
4547+
return T.ziglua_toAny(lua, a, allow_alloc, index);
4548+
}
4549+
},
4550+
else => @compileError(@typeName(T) ++ ".ziglua_toAny has invalid signature, required: fn(lua: *Lua, alloc: ?std.mem.Allocator, comptime allow_alloc: bool, index: i32) T"),
4551+
}
4552+
}
4553+
}
4554+
4555+
switch (type_info) {
44814556
.int => {
44824557
const result = try lua.toInteger(index);
44834558
return @as(T, @intCast(result));
@@ -4551,7 +4626,11 @@ pub const Lua = opaque {
45514626
return error.LuaInvalidEnumTagName;
45524627
},
45534628
.@"struct" => {
4554-
return try lua.toStruct(T, a, allow_alloc, index);
4629+
if (type_info.@"struct".is_tuple) {
4630+
return try lua.toTuple(T, a, allow_alloc, index);
4631+
} else {
4632+
return try lua.toStruct(T, a, allow_alloc, index);
4633+
}
45554634
},
45564635
.@"union" => |u| {
45574636
if (u.tag_type == null) @compileError("Parameter type is not a tagged union");
@@ -4617,6 +4696,49 @@ pub const Lua = opaque {
46174696
return result;
46184697
}
46194698

4699+
/// Converts value at given index to a zig struct tuple if possible
4700+
fn toTuple(lua: *Lua, comptime T: type, a: ?std.mem.Allocator, comptime allow_alloc: bool, raw_index: i32) !T {
4701+
const stack_size_on_entry = lua.getTop();
4702+
defer std.debug.assert(lua.getTop() == stack_size_on_entry);
4703+
4704+
const info = @typeInfo(T).@"struct";
4705+
const index = lua.absIndex(raw_index);
4706+
4707+
var result: T = undefined;
4708+
4709+
if (lua.isTable(index)) {
4710+
lua.pushValue(index);
4711+
defer lua.pop(1);
4712+
4713+
inline for (info.fields, 0..) |field, i| {
4714+
if (lua.getMetaField(-1, "__index")) |_| {
4715+
lua.pushValue(-2);
4716+
lua.pushInteger(@intCast(i + 1));
4717+
lua.call(.{ .args = 1, .results = 1 });
4718+
} else |_| {
4719+
_ = lua.rawGetIndex(-1, @intCast(i + 1));
4720+
}
4721+
defer lua.pop(1);
4722+
result[i] = try lua.toAnyInternal(field.type, a, allow_alloc, -1);
4723+
}
4724+
} else {
4725+
// taking it as vararg
4726+
const in_range = if (raw_index < 0) (index - @as(i32, info.fields.len)) >= 0 else ((index + @as(i32, info.fields.len)) - 1) <= stack_size_on_entry;
4727+
if (in_range) {
4728+
inline for (info.fields, 0..) |field, i| {
4729+
const stack_size_before_call = lua.getTop();
4730+
const idx = if (raw_index < 0) index - @as(i32, @intCast(i)) else index + @as(i32, @intCast(i));
4731+
result[i] = try lua.toAnyInternal(field.type, a, allow_alloc, idx);
4732+
std.debug.assert(stack_size_before_call == lua.getTop());
4733+
}
4734+
} else {
4735+
return error.NotInRange;
4736+
}
4737+
}
4738+
4739+
return result;
4740+
}
4741+
46204742
/// Converts value at given index to a zig struct if possible
46214743
fn toStruct(lua: *Lua, comptime T: type, a: ?std.mem.Allocator, comptime allow_alloc: bool, raw_index: i32) !T {
46224744
const stack_size_on_entry = lua.getTop();

0 commit comments

Comments
 (0)