[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: RE: Struggling with userdata concepts
- From: Jeff Smith <spammealot1@...>
- Date: Sun, 28 Aug 2011 10:38:14 +0100
Hi Thanks for taking the time to type out that example. I found it much easier to understand than the examples I had found on the net. I looked up all the API calls and it and documented it in more detail, the code worked perfectly first time when I tested it. one thing to note:
all light userdata values in a same lua (global) State share a same metatable. in other words, metatable for light userdata is not "per object".
I was less clear about the implication of this limitation, I tried expanding the code example, so that I added a new struct variable myBoo using the same structure type. As expected this worked OK as the foo_indexer is common for the 2 variables. both myFoo and myBoo variables returned unique and correct numbers in LuaI then added a new structure type and variable with 3 floats instead of 3 ints. I wrote a new indexer for that and installed it after the myFoo indexer was setup. As I half expected, this new float structure access worked OK, but broke the myFoo and myBoo variable access. Does my understanding sound correct on that ? That was expected from the limitation you mentioned ? OK, so that kind of makes light userdata pretty much useless for real world examples where more than one structure type is needed, or am I missing something here, it sounds too big a limitation so I am doubting my understanding is correct. I guess I need to look at using full userdata now as an a
lternative way to go, I didnt really follow Michals follow up post , but I have only read it once so far, I need to re-read that one Thanks again for your help Geoff
Date: Sun, 28 Aug 2011 00:54:06 +0800
From: pengzhicheng1986@gmail.com
To: lua-l@lists.lua.org
Subject: Re: Struggling with userdata concepts
于 2011-8-27 22:46, Jeff Smith 写道:
Hi
I have done a little bit of work with Lua C API bindings, that
all went pretty smoothly, but I am having great difficulty
understanding userdata and light userdata. I have not found the
examples online easy to follow or very helpful, so I am hoping
someone on this list might be kind enough to help out. The
example I want to implement is to expose to Lua a C structure
so Lua can access the individual data variables
struct foo
{
int x;
int y;
int z;
};
struct foo myFoo;
--------------------------------------------------------
-- In Lua I want to do something like
local x = myFoo.x
local y = myFoo.y
--------------------------------------------------------
As I dont want Lua to create myFoo objects, or manage their
memory, I am thinking this example should be implemented with
light userdata, but dont know how to go about this.
This example is a slightly simplified version of what I need to
do, in reality I have a C array, such as struct foo
myFoo[3];
so ultimately I would want to do something like this in Lua,
local x = myFoo[2].x.
I am not sure how much the array version complicates the
solution for the non array version ?
Any example C API code and explanation would be most appreciated
if anyone fancies brushing up their skills to try this out ?
Regards Geoff
a light userdata is just a "pointer". lua code can only do
assignment and test the equality of userdata, all other operations
(e.g. index) must be defined in C code.
simply saying, you store a C pointer into lua using light userdata,
and define various operations that can be access from lua as
metamethods.
for instance, you know, the lua code `myFoo.x' is actually syntax
suggar for 'myFoo["x"]', which is a *index* operation with a key of
the "string" type.
so if you want to access myFoo.x and myFoo.y from lua like this
------------------
local x = myFoo.x
local y = myFoo.y
------------------
you should :
1. put a light userdata, or pointer (which points to the C struct
`myFoo'), into lua, with the (global) name `myFoo'
----------------------------------
lua_pushlightuserdata(L, (void*)&myFoo);
lua_setglobal(L, "myFoo");
----------------------------------
2. define the *index* operation (e.g. as a lua_CFunction) that
accept the string "x" and "y" as key and return the x and y member
of the C struct respectively.
-----------------------------------
int foo_indexer (lua_State *L) {
struct foo * p = lua_touserdata(L, 1);
const char *key = lua_tostring(L, 2);
if (p != NULL & key != NULL) {
if ( key[0] == 'x' && key[1] == '\0') { //
key is "x"
lua_pushinteger(L, p->x);
return 1;
}
else if ( key[0] == 'y' && key[1] == '\0') { //
key is "y"
lua_pushinteger(L, p->y);
return 1;
}
}
return 0;
}
------------------------------------
3. assiociate the index operation with the userdata. through
metamethod __index
------------------------------------
lua_getglobal(L, "myFoo");
lua_newtable(L);
lua_pushcfunction(L, &foo_indexer);
lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2);
lua_pop(L, -1);
-------------------------------------
then, in lua, the global myFoo is now a lightuser data.
but lua code can only assign it to other variable, or compare it
with other value for equality, or index it,
all other operations would give a error, since we have only defined
the `__index' metamethod.
-------------------------------------
local x = myFoo.x
-- metacall foo_indexer(myFoo, "x")
mt = getmetatable(myFoo)
-- mt.__index == foo_indexer
print(type(x), type(myFoo["y"]), type(myFoo.bar),
type(myFoo[1]))
-- would print : Number Number Nil Nil
myBar = myFoo
-- assignment
assert( myBar == myFoo)
-- equality test
myFoo.x = 100
-- issue a error message something like "newindex operation
is not defined"
--------------------------------------
one thing to note:
all light userdata values in a same lua (global) State share a same
metatable.
in other words, metatable for light userdata is not "per object".
the code I show is demostrating and not tested.
the important thing is to understand the concepts.
Hopefully may help.