lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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.