@@ -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
590618pub 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