[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: best way to add field to userdata?
- From: Wesley Smith <wesley.hoke@...>
- Date: Thu, 22 Apr 2010 00:35:50 -0700
I added an extra field to the metatable to distinguish attributes from
methods like you described. To define attributes, I extended the
luaL_Reg structure to have a flag indicating if it's a method, a
settable field, a gettable field or both:
struct LuaMethod {
public:
enum MethodType {
METHOD = 0,
GET,
SET,
GETSET,
};
const char *name;
lua_CFunction func;
MethodType type;
};
template <class T>
int Udata<T> :: udata__index(lua_State *L) {
lua_getfenv(L, 1); // get userdata environment
lua_pushvalue(L, 2);
lua_rawget(L, -2); // check environment table for field
if(lua_isnil(L, -1)) {
lua_getmetatable(L, 1); // get userdata metatable
lua_pushvalue(L, 2);
lua_rawget(L, -2); // check metatable for field
if(lua_isnil(L, -1)) {
lua_pop(L, 1);
lua_pushstring(L, "getters");
lua_rawget(L, -2);
lua_pushvalue(L, 2);
lua_rawget(L, -2); // check metatable for field
// if nil, check in env table
if (lua_type(L, -1) == LUA_TFUNCTION) { //if(lua_iscfunction(L, -1)) {
lua_pushvalue(L, 1);
int err = lua_pcall(L, 1, 1, 0);
if(err) {
luaL_error(L, "error indexing %s.%s: %s\n",
T::name,
lua_tostring(L, 2),
lua_tostring(L, -1));
lua_pop(L, 1);
return 0;
}
}
}
}
return 1;
}
Here's the full source code:
http://www.mat.ucsb.edu/projects/luaAV/browser/branches/luaav3/libluaav/include/luaav_udata.hpp
wes
On Thu, Apr 22, 2010 at 12:27 AM, Ted Unangst <ted.unangst@gmail.com> wrote:
> This seems obvious, but I can't find the right info. I have a C
> module that exports a 'class' to Lua that has some methods and fields.
> (It's an image library, for context).
>
> The first thing I did was newmetatable, pushvalue, setfield(-2,
> "__index"), register(L, NULL, methods). Basically, by the book. That
> worked great for the methods:
>
> img = GetImage()
> img:resize(x, y)
> img:makepretty() -- whatever
>
> But in order to get access to the width and height, I needed to use
> getters ("img:width()", as a call) which are annoying. I want
> "img.width" to work.
>
> Currently, I instead wrote my own index method, set that in __index,
> and basically emulate register's behavior by iterating over my method
> array by hand. Then, if no function matches, I fall back on a series
> of if-else strcmp tests for known field names. This seems hackish.
>
> Alternatively, I could return a table and hang my userdata off that,
> but it seems prone to accidents.
>
> Am I missing something obvious in the documentation? Everything I've
> found only talks about adding methods.
>