From d21df8f454f5fe45a90cd68abb0894038f46da49 Mon Sep 17 00:00:00 2001
From: axdank <alexisslobodzian2@gmail.com>
Date: Mon, 2 Dec 2024 17:12:26 -0300
Subject: [PATCH 1/6] implement toTuple and others

---
 src/lib.zig | 136 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 129 insertions(+), 7 deletions(-)

diff --git a/src/lib.zig b/src/lib.zig
index 5961de8..2e1f80a 100644
--- a/src/lib.zig
+++ b/src/lib.zig
@@ -585,6 +585,34 @@ pub fn Parsed(comptime T: type) type {
     };
 }
 
+const internals = [_][]const u8{ "toStruct", "toSlice", "toTuple", "toAnyInternal" };
+
+// wrap over some internal functions of the Lua struct
+pub const Internals = blk: {
+    const StructField = std.builtin.Type.StructField;
+    var fields: [internals.len]StructField = undefined;
+    for (internals, 0..) |entry, i| {
+        const F = @field(Lua, entry);
+        const T = @TypeOf(F);
+        fields[i] = .{
+            .name = @ptrCast(entry),
+            .type = T,
+            .default_value = &F,
+            .is_comptime = false,
+            .alignment = @alignOf(T),
+        };
+    }
+
+    const TT = @Type(.{ .@"struct" = .{
+        .layout = .auto,
+        .fields = &fields,
+        .decls = &.{},
+        .is_tuple = false,
+    } });
+
+    break :blk TT{};
+};
+
 /// A Zig wrapper around the Lua C API
 /// Represents a Lua state or thread and contains the entire state of the Lua interpreter
 pub const Lua = opaque {
@@ -4352,7 +4380,27 @@ pub const Lua = opaque {
     /// Works with ints, floats, booleans, structs,
     /// tagged unions, optionals, and strings
     pub fn pushAny(lua: *Lua, value: anytype) !void {
-        switch (@typeInfo(@TypeOf(value))) {
+        const T = @TypeOf(value);
+        const type_info = @typeInfo(T);
+
+        if (type_info == .@"struct" or type_info == .@"union" or type_info == .@"enum") {
+            if (@hasDecl(T, "ziglua_pushAny")) {
+                const fnInfo = @typeInfo(@TypeOf(T.ziglua_pushAny)).@"fn";
+                switch (fnInfo.params.len) {
+                    // fn(self, lua) -> void
+                    2 => {
+                        if (@typeInfo(fnInfo.return_type.?) == .error_union) {
+                            return try value.ziglua_pushAny(lua);
+                        } else {
+                            return value.ziglua_pushAny(lua);
+                        }
+                    },
+                    else => @compileError(@typeName(T) ++ ".ziglua_pushAny has invalid signature, required: fn(self: T, lua: *Lua) void"),
+                }
+            }
+        }
+
+        switch (type_info) {
             .int, .comptime_int => {
                 lua.pushInteger(@intCast(value));
             },
@@ -4407,10 +4455,18 @@ pub const Lua = opaque {
             },
             .@"struct" => |info| {
                 lua.createTable(0, 0);
-                inline for (info.fields) |field| {
-                    try lua.pushAny(field.name);
-                    try lua.pushAny(@field(value, field.name));
-                    lua.setTable(-3);
+                if (info.is_tuple) {
+                    inline for (0..info.fields.len) |i| {
+                        try lua.pushAny(i + 1);
+                        try lua.pushAny(value[i]);
+                        lua.setTable(-3);
+                    }
+                } else {
+                    inline for (info.fields) |field| {
+                        try lua.pushAny(field.name);
+                        try lua.pushAny(@field(value, field.name));
+                        lua.setTable(-3);
+                    }
                 }
             },
             .@"union" => |info| {
@@ -4477,7 +4533,26 @@ pub const Lua = opaque {
             }
         }
 
-        switch (@typeInfo(T)) {
+        const type_info = @typeInfo(T);
+
+        if (type_info == .@"struct" or type_info == .@"union" or type_info == .@"enum") {
+            if (@hasDecl(T, "ziglua_toAny")) {
+                const fnInfo = @typeInfo(@TypeOf(T.ziglua_toAny)).@"fn";
+                switch (fnInfo.params.len) {
+                    // fn(lua_state, alloc, allow_alloc, index) -> T
+                    4 => {
+                        if (@typeInfo(fnInfo.return_type.?) == .error_union) {
+                            return try T.ziglua_toAny(lua, a, allow_alloc, index);
+                        } else {
+                            return T.ziglua_toAny(lua, a, allow_alloc, index);
+                        }
+                    },
+                    else => @compileError(@typeName(T) ++ ".ziglua_toAny has invalid signature, required: fn(lua: *Lua, alloc: ?std.mem.Allocator, comptime allow_alloc: bool, index: i32) T"),
+                }
+            }
+        }
+
+        switch (type_info) {
             .int => {
                 const result = try lua.toInteger(index);
                 return @as(T, @intCast(result));
@@ -4551,7 +4626,11 @@ pub const Lua = opaque {
                 return error.LuaInvalidEnumTagName;
             },
             .@"struct" => {
-                return try lua.toStruct(T, a, allow_alloc, index);
+                if (type_info.@"struct".is_tuple) {
+                    return try lua.toTuple(T, a, allow_alloc, index);
+                } else {
+                    return try lua.toStruct(T, a, allow_alloc, index);
+                }
             },
             .@"union" => |u| {
                 if (u.tag_type == null) @compileError("Parameter type is not a tagged union");
@@ -4617,6 +4696,49 @@ pub const Lua = opaque {
         return result;
     }
 
+    /// Converts value at given index to a zig struct tuple if possible
+    fn toTuple(lua: *Lua, comptime T: type, a: ?std.mem.Allocator, comptime allow_alloc: bool, raw_index: i32) !T {
+        const stack_size_on_entry = lua.getTop();
+        defer std.debug.assert(lua.getTop() == stack_size_on_entry);
+
+        const info = @typeInfo(T).@"struct";
+        const index = lua.absIndex(raw_index);
+
+        var result: T = undefined;
+
+        if (lua.isTable(index)) {
+            lua.pushValue(index);
+            defer lua.pop(1);
+
+            inline for (info.fields, 0..) |field, i| {
+                if (lua.getMetaField(-1, "__index")) |_| {
+                    lua.pushValue(-2);
+                    lua.pushInteger(@intCast(i + 1));
+                    lua.call(.{ .args = 1, .results = 1 });
+                } else |_| {
+                    _ = lua.rawGetIndex(-1, @intCast(i + 1));
+                }
+                defer lua.pop(1);
+                result[i] = try lua.toAnyInternal(field.type, a, allow_alloc, -1);
+            }
+        } else {
+            // taking it as vararg
+            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;
+            if (in_range) {
+                inline for (info.fields, 0..) |field, i| {
+                    const stack_size_before_call = lua.getTop();
+                    const idx = if (raw_index < 0) index - @as(i32, @intCast(i)) else index + @as(i32, @intCast(i));
+                    result[i] = try lua.toAnyInternal(field.type, a, allow_alloc, idx);
+                    std.debug.assert(stack_size_before_call == lua.getTop());
+                }
+            } else {
+                return error.NotInRange;
+            }
+        }
+
+        return result;
+    }
+
     /// Converts value at given index to a zig struct if possible
     fn toStruct(lua: *Lua, comptime T: type, a: ?std.mem.Allocator, comptime allow_alloc: bool, raw_index: i32) !T {
         const stack_size_on_entry = lua.getTop();

From 286447756b2b0f130d8ae4566d525cd1363c906d Mon Sep 17 00:00:00 2001
From: axdank <alexisslobodzian2@gmail.com>
Date: Mon, 2 Dec 2024 17:13:34 -0300
Subject: [PATCH 2/6] add tests for the new implementations

---
 src/tests.zig | 128 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 121 insertions(+), 7 deletions(-)

diff --git a/src/tests.zig b/src/tests.zig
index 6db4c20..e4b896e 100644
--- a/src/tests.zig
+++ b/src/tests.zig
@@ -2382,6 +2382,91 @@ test "toAny struct" {
     ));
 }
 
+test "toAny tuple from vararg" {
+    var lua = try Lua.init(testing.allocator);
+    defer lua.deinit();
+
+    const Tuple = std.meta.Tuple(&.{ i32, bool, i32 });
+
+    lua.pushInteger(100);
+    lua.pushBoolean(true);
+    lua.pushInteger(300);
+
+    const result = try lua.toAny(Tuple, 1);
+    try testing.expect(std.meta.eql(result, .{ 100, true, 300 }));
+
+    const result_reverse = try lua.toAny(Tuple, -1);
+    try testing.expect(std.meta.eql(result_reverse, .{ 300, true, 100 }));
+
+    const result_error = lua.toAny(Tuple, 2);
+    try testing.expectError(error.NotInRange, result_error);
+
+    const result_reverse_error = lua.toAny(Tuple, -2);
+    try testing.expectError(error.NotInRange, result_reverse_error);
+}
+
+test "toAny tuple from struct" {
+    var lua = try Lua.init(testing.allocator);
+    defer lua.deinit();
+
+    const MyType = struct {
+        foo: i32,
+        bar: bool,
+        tuple: std.meta.Tuple(&.{ i32, bool, struct { foo: bool } }),
+    };
+
+    try lua.doString(
+        \\ value = {
+        \\   ["foo"] = 10,
+        \\   ["bar"] = false,
+        \\   ["tuple"] = {100, false, {["foo"] = true}}
+        \\ }
+    );
+
+    const lua_type = try lua.getGlobal("value");
+    try testing.expect(lua_type == .table);
+    const my_struct = try lua.toAny(MyType, 1);
+    try testing.expect(std.meta.eql(
+        my_struct,
+        MyType{ .foo = 10, .bar = false, .tuple = .{ 100, false, .{ .foo = true } } },
+    ));
+}
+
+test "toAny from struct with custom toAny" {
+    var lua = try Lua.init(testing.allocator);
+    defer lua.deinit();
+
+    const MyType = struct {
+        foo: bool,
+        bar: struct {
+            const Self = @This();
+            foo: i32,
+
+            pub fn ziglua_toAny(l: *Lua, a: ?std.mem.Allocator, comptime aa: bool, i: i32) !Self {
+                return try ziglua.Internals.toStruct(l, Self, a, aa, i);
+            }
+        },
+    };
+
+    try lua.doString(
+        \\ value = {
+        \\   ["foo"] = true,
+        \\   ["bar"] = {
+        \\     ["foo"] = 12
+        \\   }
+        \\ }
+    );
+
+    const lua_type = try lua.getGlobal("value");
+    try testing.expect(lua_type == .table);
+    const my_struct = try lua.toAny(MyType, 1);
+    lua.pop(-1);
+    try testing.expect(std.meta.eql(
+        my_struct,
+        MyType{ .foo = true, .bar = .{ .foo = 12 } },
+    ));
+}
+
 test "toAny mutable string" {
     var lua = try Lua.init(testing.allocator);
     defer lua.deinit();
@@ -2591,18 +2676,47 @@ test "pushAny struct" {
     try testing.expect(value.bar == (MyType{}).bar);
 }
 
-test "pushAny anon struct" {
+test "pushAny tuple" {
+    var lua = try Lua.init(testing.allocator);
+    defer lua.deinit();
+
+    const Tuple = std.meta.Tuple(&.{ i32, bool, i32 });
+    const value: Tuple = .{ 500, false, 600 };
+
+    try lua.pushAny(value);
+
+    const result = try lua.toAny(Tuple, 1);
+    try testing.expect(std.meta.eql(result, .{ 500, false, 600 }));
+}
+
+test "pushAny from struct with custom pushAny" {
     var lua = try Lua.init(testing.allocator);
     defer lua.deinit();
 
     const MyType = struct {
-        x: i32,
-        enable: bool,
+        const Self = @This();
+        foo: i32,
+        tuple: std.meta.Tuple(&.{ i32, i32 }),
+
+        pub fn ziglua_pushAny(self: *const Self, l: *Lua) !void {
+            l.newTable();
+
+            inline for (@typeInfo(Self).@"struct".fields) |f| {
+                try l.pushAny(f.name);
+                try l.pushAny(@field(self, f.name));
+                l.setTable(-3);
+            }
+        }
     };
-    try lua.pushAny(.{ .x = @as(i32, 13), .enable = true });
-    const value = try lua.toAny(MyType, -1);
-    try testing.expect(value.x == 13);
-    try testing.expect(value.enable == true);
+
+    const value: MyType = .{ .foo = 15, .tuple = .{ 1, 2 } };
+
+    try lua.pushAny(value);
+    const my_struct = try lua.toAny(MyType, 1);
+    try testing.expect(std.meta.eql(
+        my_struct,
+        MyType{ .foo = 15, .tuple = .{ 1, 2 } },
+    ));
 }
 
 test "pushAny tagged union" {

From 1c2fb9ad93707a5639db71cb87ea7117656ea337 Mon Sep 17 00:00:00 2001
From: axdank <alexisslobodzian2@gmail.com>
Date: Tue, 3 Dec 2024 22:58:52 -0300
Subject: [PATCH 3/6] changes ziglua_{toAny, pushAny} to `fromLua` and `toLua`

---
 src/lib.zig   | 130 ++++++++++++++++++++++++++++++++++++++++++++++----
 src/tests.zig |  11 ++---
 2 files changed, 126 insertions(+), 15 deletions(-)

diff --git a/src/lib.zig b/src/lib.zig
index 2e1f80a..152e1ee 100644
--- a/src/lib.zig
+++ b/src/lib.zig
@@ -4400,6 +4400,70 @@ pub const Lua = opaque {
             }
         }
 
+        if (type_info == .@"struct" or type_info == .@"union" or type_info == .@"enum") {
+            if (@hasDecl(T, "toLua")) {
+                const toLuaArgs = .{ value, lua };
+                const fnSignature = comptime fn_sign: {
+                    var b: []const u8 = "pub fn toLua(";
+
+                    for (0..toLuaArgs.len) |i| {
+                        b = b ++ std.fmt.comptimePrint("{s}{s}", .{ @typeName(@TypeOf(toLuaArgs[i])), if (i == (toLuaArgs.len - 1)) "" else ", " });
+                    }
+
+                    b = b ++ ") !void";
+
+                    break :fn_sign b;
+                };
+
+                const fl = @field(T, "toLua");
+                const flt = @TypeOf(fl);
+                const fli = @typeInfo(flt);
+                switch (fli) {
+                    .@"fn" => |f| {
+                        const args_ok = comptime args_ok: {
+                            const f_params = f.params;
+
+                            if (f_params.len != toLuaArgs.len) break :args_ok false;
+
+                            for (0..toLuaArgs.len) |i| {
+                                if (f_params[i].type != @TypeOf(toLuaArgs[i])) break :args_ok false;
+                            }
+
+                            break :args_ok true;
+                        };
+
+                        if (args_ok) {
+                            if (f.return_type) |rt| {
+                                const rti = @typeInfo(rt);
+                                switch (rti) {
+                                    .error_union => {
+                                        if (rti.error_union.payload == void) {
+                                            try @call(.auto, fl, toLuaArgs);
+                                        } else {
+                                            @compileError("toLua invalid return type, required fn signature: " ++ fnSignature);
+                                        }
+                                    },
+                                    .void => {
+                                        @call(.auto, fl, toLuaArgs);
+                                    },
+                                    else => {
+                                        @compileError("toLua invalid return type, required fn signature: " ++ fnSignature);
+                                    },
+                                }
+                            } else {
+                                @call(.auto, fl, toLuaArgs);
+                            }
+                        } else {
+                            @compileError("toLua has invalid args, required fn signature: " ++ fnSignature);
+                        }
+                    },
+                    else => {
+                        @compileError("toLua is not a function, required fn signature: " ++ fnSignature);
+                    },
+                }
+            }
+        }
+
         switch (type_info) {
             .int, .comptime_int => {
                 lua.pushInteger(@intCast(value));
@@ -4536,18 +4600,66 @@ pub const Lua = opaque {
         const type_info = @typeInfo(T);
 
         if (type_info == .@"struct" or type_info == .@"union" or type_info == .@"enum") {
-            if (@hasDecl(T, "ziglua_toAny")) {
-                const fnInfo = @typeInfo(@TypeOf(T.ziglua_toAny)).@"fn";
-                switch (fnInfo.params.len) {
-                    // fn(lua_state, alloc, allow_alloc, index) -> T
-                    4 => {
-                        if (@typeInfo(fnInfo.return_type.?) == .error_union) {
-                            return try T.ziglua_toAny(lua, a, allow_alloc, index);
+            if (@hasDecl(T, "fromLua")) {
+                const fromLuaArgs = .{ lua, a, index };
+                const fnSignature = comptime fn_sign: {
+                    var b: []const u8 = "pub fn fromLua(";
+
+                    for (0..fromLuaArgs.len) |i| {
+                        b = b ++ std.fmt.comptimePrint("{s}{s}", .{ @typeName(@TypeOf(fromLuaArgs[i])), if (i == (fromLuaArgs.len - 1)) "" else ", " });
+                    }
+
+                    b = b ++ ") !" ++ @typeName(T);
+
+                    break :fn_sign b;
+                };
+
+                const fl = @field(T, "fromLua");
+                const flt = @TypeOf(fl);
+                const fli = @typeInfo(flt);
+                switch (fli) {
+                    .@"fn" => |f| {
+                        const args_ok = comptime args_ok: {
+                            const f_params = f.params;
+
+                            if (f_params.len != fromLuaArgs.len) break :args_ok false;
+
+                            for (0..fromLuaArgs.len) |i| {
+                                if (f_params[i].type != @TypeOf(fromLuaArgs[i])) break :args_ok false;
+                            }
+
+                            break :args_ok true;
+                        };
+
+                        if (args_ok) {
+                            if (f.return_type) |rt| {
+                                if (rt == T) {
+                                    return @call(.auto, fl, fromLuaArgs);
+                                } else {
+                                    const rti = @typeInfo(rt);
+                                    switch (rti) {
+                                        .error_union => {
+                                            if (rti.error_union.payload == T) {
+                                                return try @call(.auto, fl, fromLuaArgs);
+                                            } else {
+                                                @compileError("fromLua invalid return type, required fn signature: " ++ fnSignature);
+                                            }
+                                        },
+                                        else => {
+                                            @compileError("fromLua invalid return type, required fn signature: " ++ fnSignature);
+                                        },
+                                    }
+                                }
+                            } else {
+                                @compileError("fromLua require a fn signature: " ++ fnSignature);
+                            }
                         } else {
-                            return T.ziglua_toAny(lua, a, allow_alloc, index);
+                            @compileError("fromLua has invalid args, required fn signature: " ++ fnSignature);
                         }
                     },
-                    else => @compileError(@typeName(T) ++ ".ziglua_toAny has invalid signature, required: fn(lua: *Lua, alloc: ?std.mem.Allocator, comptime allow_alloc: bool, index: i32) T"),
+                    else => {
+                        @compileError("fromLua is not a function, required fn signature: " ++ fnSignature);
+                    },
                 }
             }
         }
diff --git a/src/tests.zig b/src/tests.zig
index e4b896e..0df8d0f 100644
--- a/src/tests.zig
+++ b/src/tests.zig
@@ -2432,7 +2432,7 @@ test "toAny tuple from struct" {
     ));
 }
 
-test "toAny from struct with custom toAny" {
+test "toAny from struct with fromLua" {
     var lua = try Lua.init(testing.allocator);
     defer lua.deinit();
 
@@ -2442,8 +2442,8 @@ test "toAny from struct with custom toAny" {
             const Self = @This();
             foo: i32,
 
-            pub fn ziglua_toAny(l: *Lua, a: ?std.mem.Allocator, comptime aa: bool, i: i32) !Self {
-                return try ziglua.Internals.toStruct(l, Self, a, aa, i);
+            pub fn fromLua(l: *Lua, a: ?std.mem.Allocator, i: i32) !Self {
+                return try ziglua.Internals.toStruct(l, Self, a, false, i);
             }
         },
     };
@@ -2460,7 +2460,6 @@ test "toAny from struct with custom toAny" {
     const lua_type = try lua.getGlobal("value");
     try testing.expect(lua_type == .table);
     const my_struct = try lua.toAny(MyType, 1);
-    lua.pop(-1);
     try testing.expect(std.meta.eql(
         my_struct,
         MyType{ .foo = true, .bar = .{ .foo = 12 } },
@@ -2689,7 +2688,7 @@ test "pushAny tuple" {
     try testing.expect(std.meta.eql(result, .{ 500, false, 600 }));
 }
 
-test "pushAny from struct with custom pushAny" {
+test "pushAny from struct with toLua" {
     var lua = try Lua.init(testing.allocator);
     defer lua.deinit();
 
@@ -2698,7 +2697,7 @@ test "pushAny from struct with custom pushAny" {
         foo: i32,
         tuple: std.meta.Tuple(&.{ i32, i32 }),
 
-        pub fn ziglua_pushAny(self: *const Self, l: *Lua) !void {
+        pub fn toLua(self: Self, l: *Lua) void {
             l.newTable();
 
             inline for (@typeInfo(Self).@"struct".fields) |f| {

From f8983a5e2756952f4c2f6857c3147e2d7dab3ac9 Mon Sep 17 00:00:00 2001
From: axdank <alexisslobodzian2@gmail.com>
Date: Wed, 4 Dec 2024 17:38:39 -0300
Subject: [PATCH 4/6] fix returns

---
 src/lib.zig | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/lib.zig b/src/lib.zig
index 152e1ee..bae0058 100644
--- a/src/lib.zig
+++ b/src/lib.zig
@@ -4438,20 +4438,20 @@ pub const Lua = opaque {
                                 switch (rti) {
                                     .error_union => {
                                         if (rti.error_union.payload == void) {
-                                            try @call(.auto, fl, toLuaArgs);
+                                            return try @call(.auto, fl, toLuaArgs);
                                         } else {
                                             @compileError("toLua invalid return type, required fn signature: " ++ fnSignature);
                                         }
                                     },
                                     .void => {
-                                        @call(.auto, fl, toLuaArgs);
+                                        return @call(.auto, fl, toLuaArgs);
                                     },
                                     else => {
                                         @compileError("toLua invalid return type, required fn signature: " ++ fnSignature);
                                     },
                                 }
                             } else {
-                                @call(.auto, fl, toLuaArgs);
+                                return @call(.auto, fl, toLuaArgs);
                             }
                         } else {
                             @compileError("toLua has invalid args, required fn signature: " ++ fnSignature);

From 46347ce337e81d81127198309d08b8af57111897 Mon Sep 17 00:00:00 2001
From: axdank <alexisslobodzian2@gmail.com>
Date: Fri, 6 Dec 2024 11:26:48 -0300
Subject: [PATCH 5/6] remove a forget block of code

---
 src/lib.zig | 17 -----------------
 1 file changed, 17 deletions(-)

diff --git a/src/lib.zig b/src/lib.zig
index bae0058..0efca1c 100644
--- a/src/lib.zig
+++ b/src/lib.zig
@@ -4383,23 +4383,6 @@ pub const Lua = opaque {
         const T = @TypeOf(value);
         const type_info = @typeInfo(T);
 
-        if (type_info == .@"struct" or type_info == .@"union" or type_info == .@"enum") {
-            if (@hasDecl(T, "ziglua_pushAny")) {
-                const fnInfo = @typeInfo(@TypeOf(T.ziglua_pushAny)).@"fn";
-                switch (fnInfo.params.len) {
-                    // fn(self, lua) -> void
-                    2 => {
-                        if (@typeInfo(fnInfo.return_type.?) == .error_union) {
-                            return try value.ziglua_pushAny(lua);
-                        } else {
-                            return value.ziglua_pushAny(lua);
-                        }
-                    },
-                    else => @compileError(@typeName(T) ++ ".ziglua_pushAny has invalid signature, required: fn(self: T, lua: *Lua) void"),
-                }
-            }
-        }
-
         if (type_info == .@"struct" or type_info == .@"union" or type_info == .@"enum") {
             if (@hasDecl(T, "toLua")) {
                 const toLuaArgs = .{ value, lua };

From 495d7361dc704789e04930ed25f0570d22521b23 Mon Sep 17 00:00:00 2001
From: axdank <alexisslobodzian2@gmail.com>
Date: Wed, 11 Dec 2024 09:22:13 -0300
Subject: [PATCH 6/6] make public some functions

---
 src/lib.zig   | 36 ++++--------------------------------
 src/tests.zig |  2 +-
 2 files changed, 5 insertions(+), 33 deletions(-)

diff --git a/src/lib.zig b/src/lib.zig
index 0efca1c..6b23cc9 100644
--- a/src/lib.zig
+++ b/src/lib.zig
@@ -585,34 +585,6 @@ pub fn Parsed(comptime T: type) type {
     };
 }
 
-const internals = [_][]const u8{ "toStruct", "toSlice", "toTuple", "toAnyInternal" };
-
-// wrap over some internal functions of the Lua struct
-pub const Internals = blk: {
-    const StructField = std.builtin.Type.StructField;
-    var fields: [internals.len]StructField = undefined;
-    for (internals, 0..) |entry, i| {
-        const F = @field(Lua, entry);
-        const T = @TypeOf(F);
-        fields[i] = .{
-            .name = @ptrCast(entry),
-            .type = T,
-            .default_value = &F,
-            .is_comptime = false,
-            .alignment = @alignOf(T),
-        };
-    }
-
-    const TT = @Type(.{ .@"struct" = .{
-        .layout = .auto,
-        .fields = &fields,
-        .decls = &.{},
-        .is_tuple = false,
-    } });
-
-    break :blk TT{};
-};
-
 /// A Zig wrapper around the Lua C API
 /// Represents a Lua state or thread and contains the entire state of the Lua interpreter
 pub const Lua = opaque {
@@ -4570,7 +4542,7 @@ pub const Lua = opaque {
     /// Converts the specified index of the lua stack to the specified
     /// type if possible and returns it
     /// optional allocator
-    fn toAnyInternal(lua: *Lua, comptime T: type, a: ?std.mem.Allocator, comptime allow_alloc: bool, index: i32) !T {
+    pub fn toAnyInternal(lua: *Lua, comptime T: type, a: ?std.mem.Allocator, comptime allow_alloc: bool, index: i32) !T {
         const stack_size_on_entry = lua.getTop();
         defer {
             if (lua.getTop() != stack_size_on_entry) {
@@ -4771,7 +4743,7 @@ pub const Lua = opaque {
     }
 
     /// Converts a lua array to a zig slice, memory is owned by the caller
-    fn toSlice(lua: *Lua, comptime ChildType: type, a: std.mem.Allocator, raw_index: i32) ![]ChildType {
+    pub fn toSlice(lua: *Lua, comptime ChildType: type, a: std.mem.Allocator, raw_index: i32) ![]ChildType {
         const index = lua.absIndex(raw_index);
 
         if (!lua.isTable(index)) {
@@ -4792,7 +4764,7 @@ pub const Lua = opaque {
     }
 
     /// Converts value at given index to a zig struct tuple if possible
-    fn toTuple(lua: *Lua, comptime T: type, a: ?std.mem.Allocator, comptime allow_alloc: bool, raw_index: i32) !T {
+    pub fn toTuple(lua: *Lua, comptime T: type, a: ?std.mem.Allocator, comptime allow_alloc: bool, raw_index: i32) !T {
         const stack_size_on_entry = lua.getTop();
         defer std.debug.assert(lua.getTop() == stack_size_on_entry);
 
@@ -4835,7 +4807,7 @@ pub const Lua = opaque {
     }
 
     /// Converts value at given index to a zig struct if possible
-    fn toStruct(lua: *Lua, comptime T: type, a: ?std.mem.Allocator, comptime allow_alloc: bool, raw_index: i32) !T {
+    pub fn toStruct(lua: *Lua, comptime T: type, a: ?std.mem.Allocator, comptime allow_alloc: bool, raw_index: i32) !T {
         const stack_size_on_entry = lua.getTop();
         defer std.debug.assert(lua.getTop() == stack_size_on_entry);
 
diff --git a/src/tests.zig b/src/tests.zig
index 0df8d0f..d61213d 100644
--- a/src/tests.zig
+++ b/src/tests.zig
@@ -2443,7 +2443,7 @@ test "toAny from struct with fromLua" {
             foo: i32,
 
             pub fn fromLua(l: *Lua, a: ?std.mem.Allocator, i: i32) !Self {
-                return try ziglua.Internals.toStruct(l, Self, a, false, i);
+                return try l.toStruct(Self, a, false, i);
             }
         },
     };