Lua Zig API

Hi !

I wanted to showcase one of my side project which was to wrap around the Lua API for Zig. I needed it for another personal project and in the end open-sourced my lua bindings. It uses the latest zig master branch.

I feel like I’ve done a good job at DX, optimization might not be the same I tried to minimize as much as possible allocations. So at runtime, the wrapper will free / allocate only what’s needed at the extra cost of walking through fields of structs etc.

The code is available here :

It was also an excuse to try out codeberg !

Here’s an example code :

// functions can take or return a struct as
// an argument !
fn functor(value: struct {
    internal: u32
}) u32 {
    std.log.debug("functor({})", .{value});

    return value.internal * value.internal;
}

const LUA_PROGRAM =
    \\function multiply(x, y)
    \\    local z = x * y
    \\    z = functor({ internal = z })
    \\    return z
    \\end
;

pub fn main(init: std.process.Init) !void {
    var state: lua.Lua = try .init(init.gpa, .{});
    defer state.deinit();
    defer {
        if (state.diag.hasErr()) {
            std.log.err("{}: {s}", .{ state.diag.err.?, state.diag.message });
        }
    }

    try state.setGlobal("functor", functor);

    const reader = std.Io.Reader.fixed(LUA_PROGRAM);
    try state.loadFromReader(reader);
    // The program must be ran once to load symbols
    try state.run();

    // Return value (here `u32`) can be a struct, string, etc.
    // If it is a string or a struct containing one, don't forget to call
    // state.free(#) on it !
    const ret = try state.call("multiply", .{ 2, 3 }, u32);

    std.log.debug("functor(2 * 3) = {}", .{ret});
}
16 Likes