@@ -585,6 +585,34 @@ pub fn Parsed(comptime T: type) type {
585
585
};
586
586
}
587
587
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
+
588
616
/// A Zig wrapper around the Lua C API
589
617
/// Represents a Lua state or thread and contains the entire state of the Lua interpreter
590
618
pub const Lua = opaque {
@@ -4352,7 +4380,27 @@ pub const Lua = opaque {
4352
4380
/// Works with ints, floats, booleans, structs,
4353
4381
/// tagged unions, optionals, and strings
4354
4382
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 ) {
4356
4404
.int , .comptime_int = > {
4357
4405
lua .pushInteger (@intCast (value ));
4358
4406
},
@@ -4407,10 +4455,18 @@ pub const Lua = opaque {
4407
4455
},
4408
4456
.@"struct" = > | info | {
4409
4457
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
+ }
4414
4470
}
4415
4471
},
4416
4472
.@"union" = > | info | {
@@ -4477,7 +4533,26 @@ pub const Lua = opaque {
4477
4533
}
4478
4534
}
4479
4535
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 ) {
4481
4556
.int = > {
4482
4557
const result = try lua .toInteger (index );
4483
4558
return @as (T , @intCast (result ));
@@ -4551,7 +4626,11 @@ pub const Lua = opaque {
4551
4626
return error .LuaInvalidEnumTagName ;
4552
4627
},
4553
4628
.@"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
+ }
4555
4634
},
4556
4635
.@"union" = > | u | {
4557
4636
if (u .tag_type == null ) @compileError ("Parameter type is not a tagged union" );
@@ -4617,6 +4696,49 @@ pub const Lua = opaque {
4617
4696
return result ;
4618
4697
}
4619
4698
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
+
4620
4742
/// Converts value at given index to a zig struct if possible
4621
4743
fn toStruct (lua : * Lua , comptime T : type , a : ? std.mem.Allocator , comptime allow_alloc : bool , raw_index : i32 ) ! T {
4622
4744
const stack_size_on_entry = lua .getTop ();
0 commit comments