Reputation: 389
I want to add some methods or properties to a lua object witch metadata was created by C API. I can't add property in normal way, for example:
local foo = libc.new()
foo.bar = "hello"
it say:
Failed to run script: attempt to index a libc_meta value (local 'foo')
So I think maybe need to modify metatable, so I change my code:
local foo = libc.new()
local mt = getmetatable(foo)
foo[bar] = "hello"
setmetable(foo, mt)
Unfortunately, it still doesn't work.
Failed to run script: bad argument #1 to 'setmetatable' (table expected, got libc_meta)
So how can I add methods or properties to this 'foo'?
BTW, c code is here:
static int libc_new(lua_State *L) {
...
lua_lib_space *libc = lua_newuserdata(L, sizeof(*libc));
libc->L = L;
libc->cb_enter = cb_enter;
libc->cb_leave = cb_leave;
luaL_getmetatable(L, "libc_meta");
lua_setmetatable(L, -2);
lib_space *lib = lib_new(enter, leave, libc);
libc->space = lib;
return 1;
}
Upvotes: 1
Views: 857
Reputation: 474436
Userdata is meant to be created by C, manipulated by C code, and for only the purposes that C code intends. Lua can talk to it, but only in the ways that C allows it to. As such, while userdata can have a metatable (and those metamethods are the only way Lua can "directly" interact with the userdata), only C functions (and the debug
library, but that's cheating) can directly manipulate that metatable. Lua is an embedded language, and C has primacy; if some C library wants to shut you out, it can.
What you can do is take the userdata and stick it in a table of your own, then give that table a metatable. In your __index
metamethod, if you have an override or new method for a particular key, then you forward the accesses to that. Otherwise, it will just access the stored userdata.
However, if what you get in the userdata is a function, then you may have a problem. See, most userdata functions take the userdata as a parameter; indeed, most are meant to be called via "ud:func_name(params). But if that
ud` is actually the table wrapper, then the first parameter passed to the function will be the wrapper, not the userdata itself.
That poses a problem. When the thing you get from the userdata is a function, you would need to return a wrapper for that function which goes through the parameters and converts any references to the wrapper table into the actual userdata.
Upvotes: 2