diff --git a/src/lib.zig b/src/lib.zig index 0c87bfc..bdc314c 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -5408,3 +5408,39 @@ pub fn exportFn(comptime name: []const u8, comptime func: anytype) CFn { } }.luaopen; } + +/// Generates a list of Lua function registrations (`FnReg`) from all +/// pub declarations in a struct type `T`. +/// +/// Example: +/// +/// ```zig +/// const MyLib = struct { +/// fn someHelper(...) { ... } // non-pub funcs skipped +/// pub fn foo(l: *Lua) void { ... } +/// pub fn bar(l: *Lua) void { ... } +/// +/// }; +/// +/// const funcs = fnRegsFromType(MyLib); +/// lua.newLib(funcs); +/// lua.setGlobal("mylib"); // mylib.foo, mylib.bar now visible +/// ``` +pub fn fnRegsFromType(comptime T: type) []const FnReg { + const decls = switch (@typeInfo(T)) { + inline .@"struct", .@"enum", .@"union", .@"opaque" => |info| info.decls, + else => @compileError("Type " ++ @typeName(T) ++ "does not allow declarations"), + }; + comptime var funcs: []const FnReg = &.{}; + inline for (decls) |d| { + if (@typeInfo(@TypeOf(@field(T, d.name))) == .@"fn") { + const reg: []const FnReg = &.{.{ + .name = d.name, + .func = comptime wrap(@field(T, d.name)), + }}; + funcs = funcs ++ reg; + } + } + const final = funcs; + return final; +} diff --git a/src/tests.zig b/src/tests.zig index 1062b43..0158c3d 100644 --- a/src/tests.zig +++ b/src/tests.zig @@ -3093,3 +3093,36 @@ test "checkNumeric and toNumeric" { _ = std.mem.indexOf(u8, string, error_msg) orelse return error.BadErrorMessage; } } + +test "function registration with fnRegsFromType" { + const lua: *Lua = try .init(testing.allocator); + defer lua.deinit(); + + const MyLib = struct { + pub fn add(l: *Lua) i32 { + const a = l.toInteger(1) catch 0; + const b = l.toInteger(2) catch 0; + l.pushInteger(a + b); + return 1; + } + pub fn neg(l: *Lua) i32 { + const a = l.toInteger(1) catch 0; + l.pushInteger(-a); + return 1; + } + }; + + // Construct function registration table at comptime from + // public decls on MyLib. + + if (zlua.lang == .lua51 or zlua.lang == .luau or zlua.lang == .luajit) { + const funcs = comptime zlua.fnRegsFromType(MyLib); + lua.newTable(); + lua.registerFns("fnregs", funcs); + } else { + lua.newLib(comptime zlua.fnRegsFromType(MyLib)); + lua.setGlobal("fnregs"); + } + try lua.doString("res = fnregs.add(100, fnregs.neg(25))"); + try expectEqual(75, lua.get(i32, "res")); +}