Skip to content

Commit 39f8df5

Browse files
authored
Merge pull request #179 from nurpax/fnregs
Add fnRegsFromStruct for comptime-generation of Lua function registrations
2 parents 31d1abd + 08bf149 commit 39f8df5

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

src/lib.zig

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5408,3 +5408,39 @@ pub fn exportFn(comptime name: []const u8, comptime func: anytype) CFn {
54085408
}
54095409
}.luaopen;
54105410
}
5411+
5412+
/// Generates a list of Lua function registrations (`FnReg`) from all
5413+
/// pub declarations in a struct type `T`.
5414+
///
5415+
/// Example:
5416+
///
5417+
/// ```zig
5418+
/// const MyLib = struct {
5419+
/// fn someHelper(...) { ... } // non-pub funcs skipped
5420+
/// pub fn foo(l: *Lua) void { ... }
5421+
/// pub fn bar(l: *Lua) void { ... }
5422+
///
5423+
/// };
5424+
///
5425+
/// const funcs = fnRegsFromType(MyLib);
5426+
/// lua.newLib(funcs);
5427+
/// lua.setGlobal("mylib"); // mylib.foo, mylib.bar now visible
5428+
/// ```
5429+
pub fn fnRegsFromType(comptime T: type) []const FnReg {
5430+
const decls = switch (@typeInfo(T)) {
5431+
inline .@"struct", .@"enum", .@"union", .@"opaque" => |info| info.decls,
5432+
else => @compileError("Type " ++ @typeName(T) ++ "does not allow declarations"),
5433+
};
5434+
comptime var funcs: []const FnReg = &.{};
5435+
inline for (decls) |d| {
5436+
if (@typeInfo(@TypeOf(@field(T, d.name))) == .@"fn") {
5437+
const reg: []const FnReg = &.{.{
5438+
.name = d.name,
5439+
.func = comptime wrap(@field(T, d.name)),
5440+
}};
5441+
funcs = funcs ++ reg;
5442+
}
5443+
}
5444+
const final = funcs;
5445+
return final;
5446+
}

src/tests.zig

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3093,3 +3093,36 @@ test "checkNumeric and toNumeric" {
30933093
_ = std.mem.indexOf(u8, string, error_msg) orelse return error.BadErrorMessage;
30943094
}
30953095
}
3096+
3097+
test "function registration with fnRegsFromType" {
3098+
const lua: *Lua = try .init(testing.allocator);
3099+
defer lua.deinit();
3100+
3101+
const MyLib = struct {
3102+
pub fn add(l: *Lua) i32 {
3103+
const a = l.toInteger(1) catch 0;
3104+
const b = l.toInteger(2) catch 0;
3105+
l.pushInteger(a + b);
3106+
return 1;
3107+
}
3108+
pub fn neg(l: *Lua) i32 {
3109+
const a = l.toInteger(1) catch 0;
3110+
l.pushInteger(-a);
3111+
return 1;
3112+
}
3113+
};
3114+
3115+
// Construct function registration table at comptime from
3116+
// public decls on MyLib.
3117+
3118+
if (zlua.lang == .lua51 or zlua.lang == .luau or zlua.lang == .luajit) {
3119+
const funcs = comptime zlua.fnRegsFromType(MyLib);
3120+
lua.newTable();
3121+
lua.registerFns("fnregs", funcs);
3122+
} else {
3123+
lua.newLib(comptime zlua.fnRegsFromType(MyLib));
3124+
lua.setGlobal("fnregs");
3125+
}
3126+
try lua.doString("res = fnregs.add(100, fnregs.neg(25))");
3127+
try expectEqual(75, lua.get(i32, "res"));
3128+
}

0 commit comments

Comments
 (0)