I want to use a Lua API which has specific callback functions when events occur, e.g. when an TCP package arrives. At first the function have to be registered but by the functions name as a string, see the sample code below
function __init__()
local dstport = 4681
local dstIP = "192.168.1.42"
-- register the callback function
register_tcp_handler('tcp_package_handler', dstIP, dstPort)
end
-- callback function
function tcp_package_handler(srcIP, srcPort, dstIP, dstPort, payload)
-- check the payload, or reset watchdog
end
It would be nice to have other variables in callback function provided by the callee, e.g. watchdog-timer or other objects.
The most simple way I could think of is to make the extravariables global, but it is the least elegant way I reckon. Closures would be helpful if I could pass the function directly, but i can not. I have to use the functions name as a string.
Considering this mechanics, is there a more elegant way to privide variables to the callback function without making them global?
EDIT: Using closures like this
function closure_tcp_package_handler(srcIP, srcPort, dstIP, dstPort, payload, packagecounter, timerobject)
function tcp_package_handler(srcIP, srcPort, dstIP, dstPort, payload)
-- do some stuff, change packagecounter, timerobject
end
return 'tcp_package_handler'
end
and use this function twice to register, e.g. with packagecounter1, timerobject1 and packagecounter2, timerobject2, only the last pair of parameters will be changed.
You're dealing with a callback infrastructure. In which case, your code is not the one invoking the handler. As such, there's no way to hide those parameters; if you can change them, so can someone else with access to the module providing the handler.
That doesn't mean that they have to be global, of course. You could make them members of a table. You could even provide setter functions to set the parameters, if you want to make sure that they only get certain parameters.
The simple form of this is as follows:
local handler_params = {}
function tcp_package_handler(srcIP, srcPort, dstIP, dstPort)
-- check `handler_params.payload`
end
--Make `handler_params` available for outside modification
How you do that last part is entirely up to you. You could have made it a global, but if this is in a module somewhere, it'd be better to make it a member of that module's table. And again, if you want to have some control over who gets to poke at it and how, you can use setter functions:
function tcp_handler_set_payload(payload)
handler_params.payload = payload
end
Related
I have a third party API that has an event listener adding function which takes as parameter a callback function to be triggered when the event occurs. I would like to pass argument to that callback function. I'm looking for Lua's equivalent of JavaScript's bind.
The Lua code:
EventListenerAddingFunction(myCallbackFunction); // I want to add a param to the callback here
How I would do it in JS:
EventListenerAddingFunction(myCallbackFunction.bind({}, myParameter));
Can this be done in Lua?
No Lua doesn't have this feature, so closest I can think of would be making a closure-wrapper:
EventListenerAddingFunction(function(...) myCallbackFunction({}, myParameter, ...) end)
This passes your parameter everytime the callback is called, all other callback parameters will be passed next. If you don't know your parameters use ... (I don't know them so I used varargs), it's better if you pass exact amount of parameters.
I'm trying to decorate multiple functions with a function decorator, and I want to get the parameters of a function that I'm gonna decorate (in this case called fun in the parameters) and I want to pass as an argument to the returned function (in this case called func) the arguments of the gotten function from the parameters (which is called fun)
So it may look like this:
local function decorator(fun)
local function func(fun.args)
-- Write here custom behaviour to add to the function 'fun'
fun(fun.args)
end
return func
end
However, obviously there is no such thing as fun.args that was just a way of explaining with more exactitude to you what I want. Take in mind this, I DON'T know the function I want to decorate, and the functions I want to decorate may be different to each other, so this would be a way of ADDING a custom behaviour to a function (as you can see in the code example above)
So, is there a way to do what I'm needing?
Lua supports varargs via .... In your case, you'd use it like this:
local function decorator(fun)
local function func(...)
-- Write here custom behaviour to add to the function 'fun'
fun(...)
end
return func
end
And if you want to use the arguments in the "custom behaviour" section, then you can do local args = {...}, and then access them numerically (e.g., args[1] would contain the first argument).
I register callback as event handler in my game, like this:
--register event handler
EventDispatcher:register("fire", mt.onPlayerFire, self)
--this is the event handler
mt:onPlayerFire()
print("play fire")
end
--unregister event handler
EventDispachter:unregister("fire", mt.onPlayerFire, self)
When the event handler is a function in module mt, it is fine to unregister it, because I can find the same function in mt to unregister it, but when I use this form:
EventDispatcher:register("fire", function() doSomething() end, nil)
I could not unregister the event handler, because it is anonymous, so I want to add some checks in my register function to prevent anonymous function as the event handler.
I have found the Proto struct in lua source code may be helpful, but I do not know what each piece means.
https://www.lua.org/source/5.3/lobject.h.html#Proto
I could not unregister the event handler, because it is anonymouse
Every function in Lua is anonymous value. So you can't unregister not because it is anonymous but because you didn't save any reference to it.
There is no way to detect inside of EventDispatcher:register() if the passed value (of function type) is also saved elsewhere. So if you really have multiple callbacks for the same event, and you want to unregister one specific callback, then you must have a way to identify that exact callback function.
That means you should either save the function value somewhere, so its own value could be used later as identifier for unregister(), as it is now, or return new callback's instance id, generated inside of register() when callback was added. Either way, there's something to be stored outside of EventDispatcher to identify exact callback.
This kind of avoids your question a bit, but it might solve your problem nonetheless.
When registering a new callback you could simply return some sort of identifying value, like an ID, a table or even the function itself. This could allow you to unregister it at a later moment.
local firehandler = EventDispatcher:register("fire", function() do('something') end)
-- Do some stuff here...
EventDispatcher:unregister(firehandler)
The downside is that you may have to change the way your event dispatcher keeps track of its registered events, but at worst this means implementing some linked list, and at best you can just use a Lua table to keep track of your handlers.
As for detecting anonymous functions, that's not really possible. Lua doesn't distinguish a function you define in-place from one stored in a variable; it's ultimately the same thing.
It might be possible by using the debug library, by comparing the file/line where a function is defined with the call stack, but that's just inviting bugs into your code and would probably be rather slow.
I am using Cmocka for unit test and that cannot be changed.
I am testing part of my software which invokes callback functions, if a value changes, indicating which data item changed and what the new value is.
The callback functions have this signature:
typedef void (* Value_changed_call_back) (int item_Id, int new_value);
For unit test, I want to register some callback functions and ensure that they are actually invoked, and that they receive the correct parameters.
I can use expect_int() in my mocks, to validate that they are invoked with the correct parameters.
But, I don't see how I can use will_return() since my call back functions are of type void (and that can't be changed).
How would I declare a mock callback function and verify that it is called with the correct parameters? Note that if the function is not called, then the test should fail.
I saw this post and thought about this in CMocka API.
You can use expect_function_call(func) to indicates which function should be called and function_called() in the callback to mark the function as called.
I'm not sure since how long this feature is available (but present in 1.1.5 version).
I answered to this question in case someone comes across this topic even if it's a 2016 ask.
I think the best way to do what you want is to create a stub for the callback and register that. Then inside the callback you set some global variable to a value. Then you would be able to assert that value that gets set in your stub function. This works so long as the assert and the callback are executed on the same thread to make sure that the assert is not a race condition.
I'm having some trouble understanding how to use coroutines properly with luabind. There's a templated function:
template<class Ret>
Ret resume_function(object const& obj, ...)
Where (Ret) is supposed to contain the values passed to yield by Lua.
My current points of confusion are:
What happens if the function returns rather than calling yield? Does resume_function return the function's return value?
How are you supposed to use this function if you don't know ahead of time which (or how many) parameters will be passed to yield? For example, if there are multiple possible yielding functions the function may call.
What is the type of Ret if multiple values are passed to yield?
Am I just entirely mistaken as to how all this works? I envision something like this. On the Lua side:
local img = loadImage("foo.png")
loadImage would be a C++ function which requests the image to be loaded in a different thread and then calls lua_yield, and some time later luabind::resume_function gets called with img as a parameter.
Should I pass "foo.png" to yield as a parameter? To a different function before I call yield, and then never pass any values to yield? What's the right way to structure this? I'm obviously misunderstanding something here.
Where (Ret) is supposed to contain the values passed to yield by Lua.
Luabind only supports single return values, so it only will return the first value passed to coroutine.yield.
What happens if the function returns rather than calling yield? Does resume_function return the function's return value?
Yes, you get its return value.
How are you supposed to use this function if you don't know ahead of time which (or how many) parameters will be passed to yield? For example, if there are multiple possible yielding functions the function may call.
That's up to you; they're your functions. You have to develop conventions about what the yielding function(s) receive as parameters, and what the function resuming the coroutine provides.
What is the type of Ret if multiple values are passed to yield?
Whatever you want it to be. It's the template parameter. The number of parameters to a function has no bearing on the return values that the function provides.
Remember: Lua functions take any number of parameters and can return anything. All Luabind can do is pass along the parameters you give it and convert the return value from Lua functions into what you expect that return value to be. Luabind will do type-checking on the return value of course. But it is your responsibility to make sure that the functions yielding/returning will return something that is convertable to the type the user provides for Ret.
loadImage would be a C++ function which requests the image to be loaded in a different thread and then calls lua_yield, and some time later luabind::resume_function gets called with img as a parameter.
If you're using Luabind, never call lua_yield directly. The proper way to yield in Luabind is to add an attribute to a function you register that will yield whenever you return from the function. The syntax is as follows:
module(L)
[
def("do_thing_that_takes_time", &do_thing_that_takes_time, yield)
];
That is, a C++ function that yields must always yield. This is a limitation of Luabind, as with regular Lua, you can choose whether to yield or not as you see fit.
Also, don't forget that Lua coroutines are not the same thing as actual threads. They are not preemptive; they will only execute when you explicitly tell them to with coroutine.resume or an equivalent resume call.
Also, you should never run the same Lua instance from multiple C/C++ threads; Lua is not thread-safe within the same instance (which more or less means the same lua_State object).
What you seem to want to do is have Lua call some function in C++ that itself spawns a thread to do some process, then have the Lua code wait until that thread is complete and then receives its answer.
To do that, you need to give to the Lua script an object that represents the C++ thread. So your loadImage function should not be using coroutine logic; it should return an object that represents the C++ thread. The Lua script can ask the object if it has completed, and if it has, it can query data from it.
The place where coroutines can come into play here is if you don't want the Lua script to wait until this is finished. That is, you're calling the Lua script every so often, but if the C++ thread isn't done, then it should just return. In which case, you can do something like this:
function loadImageAsCoroutine(imageFilename)
local cppThread = cpp.loadImage(imageFilename);
local function threadFunc(cppThread)
if(cppThread:isFinished()) then
local data = cppThread:GetImage();
return data;
else
coroutine.yield();
end
end
local thread = coroutine.create(threadFunc);
local errors, data = assert(coroutine.resume(thread, cppThread));
if(coroutine.status(thread) == "dead") then
return data;
else
return thread;
end
end
This function returns a coroutine or the image data itself. The caller of this function should check the type; if the type is "thread", then the C++ thread hasn't finished yet. Otherwise, it is the image data.
The caller of this function can pump the coroutine however much they want with some equivalent of coroutine.resume (whether it's luabind::resume_function or whatever). Each time, check the return value. It will be nil if the C++ thread hasn't finished, and not nil otherwise.