diff --git a/VM/include/lua.h b/VM/include/lua.h index d3b3b83c..dd6d9169 100644 --- a/VM/include/lua.h +++ b/VM/include/lua.h @@ -325,6 +325,9 @@ typedef void (*lua_Destructor)(lua_State* L, void* userdata); LUA_API void lua_setuserdatadtor(lua_State* L, int tag, lua_Destructor dtor); LUA_API lua_Destructor lua_getuserdatadtor(lua_State* L, int tag); +LUA_API void lua_setlightuserdataname(lua_State* L, int tag, const char* name); +LUA_API const char* lua_getlightuserdataname(lua_State* L, int tag); + LUA_API void lua_clonefunction(lua_State* L, int idx); LUA_API void lua_cleartable(lua_State* L, int idx); diff --git a/VM/include/luaconf.h b/VM/include/luaconf.h index 7a1bbb95..910e259a 100644 --- a/VM/include/luaconf.h +++ b/VM/include/luaconf.h @@ -101,6 +101,11 @@ #define LUA_UTAG_LIMIT 128 #endif +// number of valid Lua lightuserdata tags +#ifndef LUA_LUTAG_LIMIT +#define LUA_LUTAG_LIMIT 128 +#endif + // upper bound for number of size classes used by page allocator #ifndef LUA_SIZECLASSES #define LUA_SIZECLASSES 32 diff --git a/VM/src/lapi.cpp b/VM/src/lapi.cpp index cd595774..63babca2 100644 --- a/VM/src/lapi.cpp +++ b/VM/src/lapi.cpp @@ -681,6 +681,7 @@ void lua_pushboolean(lua_State* L, int b) void lua_pushlightuserdatatagged(lua_State* L, void* p, int tag) { + api_check(L, unsigned(tag) < LUA_LUTAG_LIMIT); setpvalue(L->top, p); L->top->extra[0] = tag; api_incr_top(L); @@ -1427,6 +1428,24 @@ lua_Destructor lua_getuserdatadtor(lua_State* L, int tag) return L->global->udatagc[tag]; } +void lua_setlightuserdataname(lua_State* L, int tag, const char* name) +{ + api_check(L, unsigned(tag) < LUA_LUTAG_LIMIT); + api_check(L, !L->global->lightuserdataname[tag]); // renaming not supported + if (!L->global->lightuserdataname[tag]) + { + L->global->lightuserdataname[tag] = luaS_new(L, name); + luaS_fix(L->global->lightuserdataname[tag]); // never collect these names + } +} + +const char* lua_getlightuserdataname(lua_State* L, int tag) +{ + api_check(L, unsigned(tag) < LUA_LUTAG_LIMIT); + const TString* name = L->global->lightuserdataname[tag]; + return name ? getstr(name) : nullptr; +} + void lua_clonefunction(lua_State* L, int idx) { luaC_checkGC(L); diff --git a/VM/src/lstate.cpp b/VM/src/lstate.cpp index 161dcda0..858f61a3 100644 --- a/VM/src/lstate.cpp +++ b/VM/src/lstate.cpp @@ -210,6 +210,8 @@ lua_State* lua_newstate(lua_Alloc f, void* ud) g->mt[i] = NULL; for (i = 0; i < LUA_UTAG_LIMIT; i++) g->udatagc[i] = NULL; + for (i = 0; i < LUA_LUTAG_LIMIT; i++) + g->lightuserdataname[i] = NULL; for (i = 0; i < LUA_MEMORY_CATEGORIES; i++) g->memcatbytes[i] = 0; diff --git a/VM/src/lstate.h b/VM/src/lstate.h index ed73d3d8..808f57b9 100644 --- a/VM/src/lstate.h +++ b/VM/src/lstate.h @@ -197,6 +197,7 @@ typedef struct global_State struct Table* mt[LUA_T_COUNT]; // metatables for basic types TString* ttname[LUA_T_COUNT]; // names for basic types TString* tmname[TM_N]; // array with tag-method names + TString* lightuserdataname[LUA_LUTAG_LIMIT]; // names for tagged lightuserdata TValue pseudotemp; // storage for temporary values used in pseudo2addr diff --git a/VM/src/ltm.cpp b/VM/src/ltm.cpp index 927a535b..bd7ee8e4 100644 --- a/VM/src/ltm.cpp +++ b/VM/src/ltm.cpp @@ -129,6 +129,13 @@ const TString* luaT_objtypenamestr(lua_State* L, const TValue* o) if (ttisstring(type)) return tsvalue(type); } + if (ttislightuserdata(o) && o->extra[0] != 0) + { + const TString* name = L->global->lightuserdataname[o->extra[0]]; + + if (name) + return name; + } else if (Table* mt = L->global->mt[ttype(o)]) { const TValue* type = luaH_getstr(mt, L->global->tmname[TM_TYPE]); diff --git a/tests/Conformance.test.cpp b/tests/Conformance.test.cpp index e47ccc8e..7b5e2b5f 100644 --- a/tests/Conformance.test.cpp +++ b/tests/Conformance.test.cpp @@ -1684,6 +1684,11 @@ TEST_CASE("LightuserdataApi") CHECK(lua_tolightuserdatatagged(L, -1, 0) == nullptr); CHECK(lua_tolightuserdatatagged(L, -1, 1) == value); + lua_setlightuserdataname(L, 1, "id"); + CHECK(!lua_getlightuserdataname(L, 0)); + CHECK(strcmp(lua_getlightuserdataname(L, 1), "id") == 0); + CHECK(strcmp(luaL_typename(L, -1), "id") == 0); + globalState.reset(); }