tags:

views:

155

answers:

3

I'd like to embed lua to allow scripting in my C++ application. In particular, I have two structs which I'd like to pass as arguments to a given lua function. One will be read-only, the other will be read/write. Highly simplified examples of these structs follow:

struct inData
{
    int x;
    int y;
    //many other fields follow
};

struct outData
{
    int a;
    double b;
    //other fields follow
};

Both of these structs are created in the C++ code and will be processed there both before and after calling the lua functions. How can I pass these structs to a lua function such that the function can do things like this:

if(inData.x > 5) then outData.a = 1 end

and have the outData instance actually retain the changes after returning from the lua function?

A: 

You can use a userdata and put a outdata* in it. You can set custom functions on them, including a metatable. I'm not going to go through it because it's SO MUCH boilerplate/glue code. Basically, you make the outdata on the heap, you make the light userdata point to it (via an incredibly evil cast), then you set a custom metatable and use __index to make the data accesses happen with a custom function.

Basically, it is doable but boring as shit. Also dangerous because Lua doesn't understand any C (or C++) types and you're dealing with void*s all the time.

DeadMG
One comment - light userdata [does not have individual metatable](http://www.lua.org/manual/5.1/manual.html#lua_pushlightuserdata). The usual way of doing this is creating full userdata, which is of size sizeof(void*), and contains a pointer to the original structure. Full userdata can have a custom metatable - the rest of the comment applies, except for the comment about being boring and a lot of boilerplate code - in my experience, it's much better than in some other languages.
MiKy
@MikKy: You're right about the userdata. There's a reason I stopped using Lua and it's because the API and language limitations make no sense. As for some other languages, I would truly shudder to imagine what you've come across that involves more tedious repetitive code than Lua boilerplate.
DeadMG
+4  A: 

boring + boilerplate + multi-language = SWIG.

http://www.swig.org/Doc1.3/Lua.html#Lua_nn13

Ben Voigt
So this appears to generate wrappers for structs etc. I'm still not clear on passing an existing struct from C into lua. In the linked example the struct is instantiated in the lua function, which is not what I'm trying to do.
idontwanttortfm
Section "23.3.9 Pointers, references, values, and arrays" discusses returning structs created by C++ code, either by pointer or by value. Does that cover your requirement?
Ben Voigt
Also http://stackoverflow.com/questions/884435/pass-variables-between-c-and-lua-via-swig There are actually quite a few C++/Lua/SWIG questions here on SO, might be worth your time reading some of them.
Ben Voigt
I'm sorry, I may not be explaining myself well or misunderstanding how this works. That section _also_ shows the object being created inside the lua code. I'm asking how an existing struct instance in my C code (let's say inside main) can be passed into a lua function which would then read and or write to this struct instance. I'm not clear on how I push this instance from C to make it usable inside lua.
idontwanttortfm
I'm talking about the very last paragraph of that section, where a C++ function allocates a struct and returns it to Lua via pointer.
Ben Voigt
Or maybe `SWIG_NewPointerObj` in section 23.5.2 is what you're after, if the C++ needs to put the structure pointer into an argument list when calling a Lua function.
Ben Voigt
SWIG_NewPointerObj was the missing piece. Thanks so much for all the help.
idontwanttortfm
A big advantage of SWIG is that it is easy to also generate interfaces to Perl, Python, R, Matlab, and more. A total of 30 or so languages supported the last time I checked.
RBerteig
+1  A: 

You could also create a Lua table that reflects this same data structure for passing information between C and Lua.

Judge Maygarden
So you're suggesting I push each attribute name and value onto lua's stack to create a lua table, then pull them all back out and copy them back into the struct after the function returns? If so, that seems horribly inefficient. If not, could you elaborate on this suggestion at all?
idontwanttortfm
Yes, that is what I am suggesting. As for performance, that depends on usage. It seems to me that a C callback to access each struct field in a userdata would require more total overhead than simply copying the values to the Lua state up front.
Judge Maygarden