coroutine¶
resumable/yielding functions from Lua
A coroutine
is a reference to a function in Lua that can be called multiple times to yield a specific result. It is run on the lua_State that was used to create it (see thread for an example on how to get a coroutine that runs on a thread separate from your usual “main” lua_State).
The coroutine
object is entirely similar to the protected_function object, with additional member functions to check if a coroutine has yielded (call_status::yielded) and is thus runnable again, whether it has completed (call_status::ok) and thus cannot yield anymore values, or whether it has suffered an error (see status() and call_status’s error codes).
For example, you can work with a coroutine like this:
function loop()
while counter ~= 30
do
coroutine.yield(counter);
counter = counter + 1;
end
return counter
end
This is a function that yields:
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script_file("co.lua");
sol::coroutine cr = lua["loop"];
for (int counter = 0; // start from 0
counter < 10 && cr; // we want 10 values, and we only want to run if the coroutine "cr" is valid
// Alternative: counter < 10 && cr.valid()
++counter) {
// Call the coroutine, does the computation and then suspends
int value = cr();
}
Note that this code doesn’t check for errors: to do so, you can call the function and assign it as auto result = cr();
, then check result.valid()
as is the case with protected_function. Finally, you can run this coroutine on another thread by doing the following:
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script_file("co.lua");
sol::thread runner = sol::thread::create(lua.lua_state());
sol::state_view runnerstate = runner.state();
sol::coroutine cr = runnerstate["loop"];
for (int counter = 0; counter < 10 && cr; ++counter) {
// Call the coroutine, does the computation and then suspends
int value = cr();
}
The following are the members of sol::coroutine
:
members¶
coroutine(lua_State* L, int index = -1);
Grabs the coroutine at the specified index given a lua_State*
.
call_status status() const noexcept;
Returns the status of a coroutine.
bool error() const noexcept;
Checks if an error occured when the coroutine was run.
bool runnable () const noexcept;
explicit operator bool() const noexcept;
These functions allow you to check if a coroutine can still be called (has more values to yield and has not errored). If you have a coroutine object coroutine my_co = /*...*/
, you can either check runnable()
or do if ( my_co ) { /* use coroutine */ }
.
template<typename... Args>
protected_function_result operator()( Args&&... args );
template<typename... Ret, typename... Args>
decltype(auto) call( Args&&... args );
template<typename... Ret, typename... Args>
decltype(auto) operator()( types<Ret...>, Args&&... args );
Calls the coroutine. The second operator()
lets you specify the templated return types using the my_co(sol::types<int, std::string>, ...)
syntax. Check status()
afterwards for more information about the success of the run or just check the coroutine object in an ifs tatement, as shown above.