Userdata, Registry and Advanced C API
34.1 Full Userdata with a Metatable (a C "Class")
typedef struct { double x, y; } Point;
#define POINT_MT "mylib.Point"
static int point_new(lua_State *L) {
double x = luaL_checknumber(L, 1), y = luaL_checknumber(L, 2);
Point *p = (Point *)lua_newuserdatauv(L, sizeof(Point), 0); // 5.4 (lua_newuserdata in older versions)
p->x = x; p->y = y;
luaL_setmetatable(L, POINT_MT);
return 1;
}
static Point *checkpoint(lua_State *L, int i) { return (Point *)luaL_checkudata(L, i, POINT_MT); }
static int point_len(lua_State *L) { Point *p = checkpoint(L, 1); lua_pushnumber(L, sqrt(p->x*p->x + p->y*p->y)); return 1; }
static int point_tostring(lua_State *L) { Point *p = checkpoint(L, 1); lua_pushfstring(L, "Point(%f, %f)", p->x, p->y); return 1; }
static int point_gc(lua_State *L) { /* free external resources here */ return 0; }
static const luaL_Reg point_methods[] = {
{"length", point_len}, {"__tostring", point_tostring}, {"__gc", point_gc}, {NULL, NULL}
};
int luaopen_point(lua_State *L) {
luaL_newmetatable(L, POINT_MT); // registry["mylib.Point"] = metatable
luaL_setfuncs(L, point_methods, 0);
lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); // methods via __index = metatable
lu
…local point = require("point")
local p = point.new(3, 4)
print(p, p:length()) --> Point(3.0, 4.0) 5.0 (lua_pushfstring formats %f like Lua floats)34.2 Registry, References and Light Userdata
// Keep a reference to a Lua value (e.g., a callback) from C
lua_pushvalue(L, 1); // the callback function
int ref = luaL_ref(L, LUA_REGISTRYINDEX); // store it, get an integer handle
// later:
lua_rawgeti(L, LUA_REGISTRYINDEX, ref); // push it back
lua_pcall(L, 0, 0, 0);
luaL_unref(L, LUA_REGISTRYINDEX, ref); // release
lua_pushlightuserdata(L, some_c_pointer); // a plain pointer value (no metatable per value, not collected)34.3 Threads, Continuations and Memory
lua_newthread creates coroutines from C. lua_resume / lua_yield / lua_yieldk let C functions participate in coroutines. Continuations (lua_callk, lua_pcallk) allow yielding across C calls (5.2+).
lua_newstate(alloc, ud) with a custom allocator enables memory limits and tracking.
One lua_State is not thread-safe. Use one state per OS thread, or lock externally (lua_lock/lua_unlock macros when compiling Lua). Libraries such as Lanes and effil provide multi-state threading.