Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Query Lua userdata type from C

Tags:

types

lua

I have a Lua userdata object with a certain metatable type (e.g. "stackoverflow.test"). From C code, I want to be able to check exactly which type it is, and behave differently depending on the results. Is there a nice handy function (rather like luaL_checkudata, but without erroring if the answer isn't what you want) that let's me query the metatable type name of the userdata? If not, I guess I need to use lua_getmetatable, but then I'm a bit unclear how I determine the name of the metatable that's just been added to the stack.

Just to clarify: I'm using Lua 5.1, where the behaviour of luaL_checkudata was changed. I understand that in 5.0 it didn't used to error.

like image 991
andygeers Avatar asked Apr 07 '09 18:04

andygeers


2 Answers

You could always store a marker field in the metatable with a light userdata value unique to your module.

static const char *green_flavor = "green";
...
void my_setflavor(lua_State *L, void *flavor) {
  lua_pushlightuserdata(L,flavor);
  lua_pushlstring(L,"_flavor");
  lua_rawset(L,-3);
}

void my_isflavor(lua_State *L, void *flavor) {
  void *p = NULL;
  lua_pushlstring(L,"_flavor");
  lua_rawget(L,-2);
  p = lua_touserdata(L,-1);
  lua_pop(L,1);
  return p == flavor;
}

Then you can use my_setflavor(L,&green_flavor) to set the _flavor field of the table at the top of the stack, and my_isflavor(L,&red_flavor) to test the _flavor field of the table at the top of the stack.

Used this way, the _flavor field can only take on values that can be created by code in the module that has the symbol green_flavor in scope, and looking up the field and testing its value only required one table lookup aside from retrieval of the metatable itself. Note that the value of the variable green_flavor does not matter, since only its address is actually used.

With several distinct flavor variables available to use as sentinal values, the _flavor field can be used to distinguish several related metatables.

All of that said, a natural question is "why do this at all?" After all, the metatable could easily contain all of the information it needs to get the appropriate behavior. It can readily hold functions as well as data, and those functions can be retrieved and called from C as well as Lua.

like image 109
RBerteig Avatar answered Sep 20 '22 02:09

RBerteig


You'll use lua_getmetatable and lua_equal for testing that the tables are the same.

In my opinion, Lua should give more support to this kind of type-extending things. As of now, it's really on the responsibility of the Lua/C(++) wrapper system to do that.

In a wrapper I've done recently (as part of a commercial project) I do class::instance(L,index) to get userdata pointers of a particular type. In other words, that method checks that it's userdata and that the metatable is also right. If not, it returns NULL.

The way Lua could help all this is if the metatable had a standard field for extended type information (s.a. __type). This could be used so that type() itself would return "userdata", "xxx" (two values, currently returning only one). This would remain compatible with most of current code. But this is just hypothetical (unless you do a custom type() and implement this on your own).

like image 35
akauppi Avatar answered Sep 20 '22 02:09

akauppi