Reputation: 267
I'm a newbie to Lua
I have a C function registered to Lua which looks like this:
call(obj, "func", param0, param1)
In the call()
:
obj
(and all params) are fixed wrapper type (similar to boost::any
)Because of that, we can't do simple class member register using regular Lua bind tools (luabind, luabridge, etc)
Here's the question:
How can we simplify the Lua call to be like this:
obj.func(param0, param1)
or
obj:func(param0, param1)
?
Thanks.
Upvotes: 3
Views: 328
Reputation: 3000
You have to set a metatable on each obj
you create (assuming it is userdata under your control and has no metatable) and override __index
metamethod in it:
local cache = { }
debug.setmetatable(obj, {
__index = function (obj, k)
return function (obj, ...) -- or (...) for [non-canonical] .-syntax
return call(obj, k, ...)
end
-- malloc-optimized version --
local f = cache[k] or function (obj, ...) return call(obj, k, ...) end
cache[k] = f
return f
end,
__metatable = "whatever",
})
f = obj.func
f(obj, param0, param1) --> call(obj, 'func', param0, param1)
obj:func(param0, param1) --> the same via syntactic sugar
If obj
already has a metatable, then that metatable has to be modified in a similar way.
The same may be done via C interface, so you can combine obj
creation with __index
setup.
Update on C side:
If creation function is in external lib, then you have no options except catching all object appearance points (return values and values in tables passed as arguments) and wrap there as described above.
If creation function is under your control, you can see something like that there:
ud = lua_newuserdata(L, sizeof(object));
*ud = object;
// this part is missing if objects have no metatable at all
luaL_getmetatable(L, tname); // or 'if (luaL_newmetatable(L, tname)) { ... }'
lua_setmetatable(L, -2);
return 1;
You have to add the __index metamethod at where metatable is created:
...somewhere in the code, maybe right after *ud = object
line...
if (luaL_newmetatable(L, tname)) {
... original metatable setup ...
int res = luaL_loadstring(L,
"return function (obj, k)\n"
" return function (obj, ...)\n"
" return call(obj, k, ...)\n"
" end\n"
"end\n");
assert(res == 0);
lua_call(L, 0, 1);
lua_setfield(L, -2, "__index");
}
If your userdata has no metatable at all, it has to be created and set.
If you want to get rid of global symbol call
, then pass its C implementation as an argument to luaL_loadstring'ed chunk:
luaL_loadstring(L, "local call = ...\n return function (obj, k)\n" ...);
lua_pushcfunction(L, l_call);
lua_call(L, 1, 1); // instead of (0, 1)
Then call
will be localized into the closure.
Upvotes: 2