I am working on a project written in C++ which uses Lua as a scripting language.
In order to facilitate debugging we implemented a network debugger which receives Lua code, runs it, encodes the return values in Json and sends that string back.
I managed to implement that for tables, but now I am stuck with variables stored in userdata.
E.g. I have this Lua code:
Elements.Avatar.testVar = 5
Elements.testVar = 15
return Elements
// result
{
"result0": "{Application:userdata; Avatar:userdata; Physics:userdata; testVar:15; }"
}
Application, Avatar and Physics are objects that have been created in C++. The two testVars however have been created in the script above.
Elements is a table, so I can list all elements, but Avatar.testVar seems to be hidden because Avatar is a LUA_TUSERDATA.
Does anyone have an idea how I can detect variables that have been added to userdata in Lua?
There is no such thing as a "variable stored in userdata", At least, not as far as Lua is concerned. From Lua's perspective, userdata is a giant black box. All Avatar.testVar = 5 does is call the metamethod __newindex in Avatar with the string testVar and the new value 15. How your C++ metamethod (because only C++ code can put metamethods on userdata) interprets this is entirely up to your code.
So it can't be done from Lua. Your code will need to provide debugging hooks. Lua 5.2 allows you to implement the __pairs and __ipairs metamethods, which the pairs and ipairs functions can use to iterate over your values. Outside of that, you're on your own for querying what does and doesn't exist in a userdata.
Related
From an in-app server, I receive a table and inside this table there's a key marked as userdata. I red this type is there to allow arbitrary C data to be stored inside Lua variables. Is it possible to read/access its content from Lua?
Lua can't read data from userdata, unless you write native functions that will read and return bytes from userdata in some way you will find convenient - as array of numbers, as string, or maybe just returning single byte at specified index.Maybe your host app/framework already has these functions, but Lua itself definitely can't do that.
Corona SDK's page for userdata only quotes Lua's doc, telling basically the same - there's no operations on userdata in Lua, except assignment and identity test.
I use LuaJit for extending a plain C application (using the Lua C API). The host application does manage memory for a lot of objects that I have written wrappers for in Lua.
Now I would like to be able to delete objects from within the lua function, i.e. implement a delete function. I would like to illustrate the problem at hand with the following outline of the problem.
Basically my lua user data structure looks something like this.
struct my_lua_container {
size_t obj_db_index;
};
where obj_db_index is an index for the local object database. With the Lua C API I have created a lua-function query_object(...) that retrieves a lua metatable based on this user data and offering an API for managing the db object.
I am now planning to introduce a method my_db_object:delete() in the metatable API. :delete() could invalidate my_db_object by overwriting the variable with 0 or setting another member variable. The problem however is, that all references to the deleted object ought to be invalidated. Consider this lua code:
local p = query_object("1")
local q = query_object("1")
p:delete()
q:do_something() -- <=== q still contains a obj_db_index
Now I wonder how to solve this potential conflict. The two main problems are:
An invalid obj_db_index could be an invalid index. This is actually probably caught by the code already, so it isn't pretty but alright
after deletion, the index might be reused and this could lead to subtle errors when other references still use the old index.
What are strategies to deal with this?
My idea might be a little time-consuming but this would be ok in the event of deletion:
Is there some Introspection that I can perform on user data objects? Like iterating over all user data objects with the same type in order to invalidate my_db_index when the deletion is triggered
Maybe a little late, but… The solution is to put new objects into weak table and never create objects already stored there.
-- this should be really C, but for readability, we write it in Lua pseudocode
registry.my_cache = setmetatable({ }, { __mode = "v" })
function push_object(db_id)
local object = registry.my_cache[db_id]
if object == nil then
object = lua_newuserdata(db_id)
registry.my_cache[db_id] = object
end
end
assert(push_object(1) == push_object(1))
Now only unique db_id's go from C side to Lua side, problem almostly disappeared.
But there is one more detail to take care of. Garbage-collection of userdata has two phases: finalization and removal from weak tables. There are moments, when userdata is finalized, but still present in weak table, so the code above may return finalized userdata to the user. Additional check should be made, and if ud is finalized, it should be manually removed from table first.
function push_object(db_id)
local object = registry.my_cache[db_id]
-- check vitality first
if is_finalized(object) then
registry.my_cache[db_id] = nil
object = nil
end
if object == nil then
object = lua_newuserdata(db_id)
registry.my_cache[db_id] = object
end
end
How you know whether userdata is finalized is up to your implementation of finalization method (metatable.__gc).
I am using inspect.lua to inspect table to string.
But, if the value is a userdata, it returns just <userdata 1>
I really need to know what the userdata type is, what the userdata value is, it's very important for debuging, I don't want do it in any IDE, I just want something can help me debug by print staffs.
You cannot.
From the manual :
The type userdata is provided to allow arbitrary C data to be stored in Lua variables. A userdata value is a pointer to a block of raw memory. [...] Userdata has no predefined operations in Lua, except assignment and identity test.
As indicated by #Eric, the only thing you can do from Lua is inspect the metatable :
print(inspect(getmetatable(someuserdata)))
If you are using the C API, you should be able to register a custom function that prints whatever is held by the block.
If the userdata metatable was created with luaL_newmetatable it contains an entry __name containing the userdatas type (since Lua version 5.3), see https://www.lua.org/manual/5.3/manual.html#luaL_newmetatable. Unfortunately this feature is still not widely used.
This is a sort of followup to my previous question about nested registered C functions found here:
Trying to call a function in Lua with nested tables
The previous question gave me the answer to adding a nested function like this:
dog.beagle.fetch()
I also would like to have variables at that level like:
dog.beagle.name
dog.beagle.microchipID
I want this string and number to be allocated in C and accessible by Lua. So, in C code, the variables might be defined as:
int microchipIDNumber;
char dogname[500];
The C variables need to be updated by assignments in Lua and its value needs to be retrieved by Lua when it is on the right of the equal sign. I have tried the __index and __newindex metamethod concept but everything I try seems to break down when I have 2 dots in the Lua path to the variable. I know I am probably making it more complicated with the 2 dots, but it makes the organization much easier to read in the Lua code. I also need to get an event for the assignment because I need to spin up some hardware when the microchipIDNumber value changes. I assume I can do this through the __newindex while I am setting the value.
Any ideas on how you would code the metatables and methods to accomplish the nesting? Could it be because my previous function declarations are confusing Lua?
The colon operator (:) in Lua is used only for functions. Consider the following example:
meta = {}
meta["__index"] = function(n,m) print(n) print(m) return m end
object = {}
setmetatable(object,meta)
print(object.foo)
The index function will simply print the two arguments it is passed and return the second one (which we will also print, because just doing object.foo is a syntax error). The output is going to be table: 0x153e6d0 foo foo with new lines. So __index gets the object in which we're looking up the variable and it's name. Now, if we replace object.foo with object:foo we get this:
input:5: function arguments expected near ')'
This is the because : in object:foo is syntactic sugar for object.foo(object), so Lua expects that you will provide arguments for a function call. If we did provide arguments (object:foo("bar")) we get this:
table: 0x222b3b0
foo
input:5: attempt to call method 'foo' (a string value)
So our __index function still gets called, but it is not passed the argument - Lua simply attemps to call the return value. So don't use : for members.
With that out of the way, let's look at how you can sync variables between Lua and C. This is actually quite involved and there are different ways to do it. One solution would be to use a combination of __index and __newindex. If you have a beagle structure in C, I'd recommend making these C functions and pushing them into the metatable of a Lua table as C-closures with a pointer to your C struct as an upvalue. Look at this for some info on lua_pushcclosure and this on closures in Lua in general.
If you don't have a single structure you can reference, it gets a lot more complicated, since you'll have to somehow store pairs variableName-variableLocation on the C side and know what type each is. You could maintain such a list in the actual Lua table, so dog.beagle would be a map of variable name to one or two something's. There a couple of options for this 'something'. First - one light user data (ie - a C pointer), but then you'll have the issue of figuring out what that is pointing to, so that you know what Lua type to push in for __index and what to pop out for __newindex . The other option is to push two functions/closures. You can make a C function for each type you'll have to handle (number, string, table, etc) and push the appropriate one for each variable, or make a uber-closure that takes a parameter what type it's being given and then just vary the up-values you push it with. In this case the __index and __newindex functions will simply lookup the appropriate function for a given variable name and call it, so it would be probably easiest to implement it in Lua.
In the case of two functions your dog.beagle might look something like this (not actual Lua syntax):
dog.beagle = {
__metatable = {
__index = function(table,key)
local getFunc = rawget(table,key).get
return getFunc(table,key)
end
__newindex = function(table,key,value)
local setFunc = rawget(table,key).set
setFunc(table,key,value)
end
}
"color" = {
"set" = *C function for setting color or closure with an upvalue to tell it's given a color*,
"get" = *C function for getting color or closure with an upvalue to tell it to return a color*
}
}
Notes about the above: 1.Don't set an object's __metatable field directly - it's used to hide the real metatable. Use setmetatable(object,metatable). 2. Notice the usage of rawget. We need it because otherwise trying to get a field of the object from within __index would be an infinite recursion. 3. You'll have to do a bit more error checking in the event rawget(table,key) returns nil, or if what it returns does not have get/set members.
Calling a Lua function from C is fairly straight forward but is there a way to store a Lua function somewhere for later use? I want to store user defined Lua functions passed to my C function for use on events, similar to how the Connect function works in wxLua.
check the registry (luaL_ref()). it manages a simple table that lets you store any Lua value (like the function), and refer to it from C by a simple integer.
Building on Javier's answer, Lua has a special universally-accessible table called the registry, accessible through the C API using the pseudo-index LUA_REGISTRYINDEX. You can use the luaL_ref function to store any Lua value you like in the registry (including Lua functions) and receive back an integer that can be used to refer to it from C:
// Assumes that the function you want to store is on the top of stack L
int function_index = luaL_ref(L, LUA_REGISTRYINDEX);
The easiest way to do this is for your function to take a "name" and the lua function text. Then you create a table in the interpreter (if it doesn't exist) and then store the function in the table using the named parameter.
In your app just keep hold of a list of function names tied to each event. When the event fires just call all the functions from your table whose key matches the names in the list.