A primer::coroutine is a primer::lua_ref
which represents a lua coroutine, or thread, as they are variously called
in the documentation.
In lua, a coroutine is like a function call which is permitted to yield, rather than return a value or
produce an error. yield
stops the execution at the point of yield. If the coroutine is "resumed"
later, then execution starts up again at the yield point, not at the beginning
of the function.
A primer::coroutine, unlike a general coroutine,
primer::bound_function.
primer::coroutine is merely a helper object to
give a nice interface for "calling" the coroutine, similar to
primer::bound_function. It abstracts away the
details of manipulating thread stacks.
The coroutine can be called again and again, provided that it yields each
time. After it returns or produces an error, it goes to an empty state
and needs to be recreated from a primer::bound_function.
Not all uses of coroutines are well-served by the primer::coroutine
object, this is only good for certain purposes. You may be better off using
lua thread objects directly in some cases. Note that you can still easily
use lua_ref and bound_function in such cases.
class coroutine { lua_ref ref_; lua_State * thread_stack_; public: // Special member functions coroutine() noexcept : ref_(), thread_stack_(nullptr) {} coroutine(coroutine &&) noexcept = default; coroutine & operator=(coroutine &&) noexcept = default; ~coroutine() noexcept = default; // Noncopyable, delete these. coroutine(const coroutine &) = delete; coroutine & operator=(const coroutine &) = delete; // Construct from bound_functionexplicit coroutine(const bound_function & bf);
explicit operator bool() const noexcept { return thread_stack_ && ref_; }
lua_State * lock() const noexcept { return thread_stack_ ? ref_.lock() : nullptr; }
void reset() noexcept; void swap(coroutine & other) noexcept; // Call the coroutine. // // Use `call_no_ret`, `call_one_ret`, or `call` to select // how many return values you expect, any extras are discarded. // // If called with a sequence of C++ values, they will become the function // call arguments, using primer::push. // // If a lua_ref_seq is passed, then its members will be pushed in succession. // // These functions catch any lua errors and do not throw exceptions. template <typename... Args> expected<void> call_no_ret(Args &&... args) noexcept; expected<void> call_no_ret(lua_ref_seq &) noexcept; expected<void> call_no_ret(lua_ref_seq const &) noexcept; expected<void> call_no_ret(lua_ref_seq &&) noexcept; template <typename... Args> expected<lua_ref> call_one_ret(Args &&... args) noexcept; expected<lua_ref> call_one_ret(lua_ref_seq &) noexcept; expected<lua_ref> call_one_ret(lua_ref_seq const &) noexcept; expected<lua_ref> call_one_ret(lua_ref_seq &&) noexcept; template <typename... Args> expected<lua_ref_seq> call(Args &&... args) noexcept; expected<lua_ref_seq> call(lua_ref_seq &) noexcept; expected<lua_ref_seq> call(lua_ref_seq const &) noexcept; expected<lua_ref_seq> call(lua_ref_seq &&) noexcept; };
Note: Can cause lua memory allocation failure |
|
Check if the coroutine is valid to call |
|
Obtain pointer to underlying lua state, if still valid to call. |
|
Reset to the empty state |
![]() |
Caution |
|---|---|
As usual, this object is not thread-safe. |