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.