PrevUpHomeNext

class coroutine

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::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.

Synopsis
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_function
  1explicit coroutine(const bound_function & bf);

  2explicit operator bool() const noexcept { return thread_stack_ && ref_; }

  3lua_State * lock() const noexcept {
    return thread_stack_ ? ref_.lock() : nullptr;
  }

  4void 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;
};

1

Note: Can cause lua memory allocation failure

2

Check if the coroutine is valid to call

3

Obtain pointer to underlying lua state, if still valid to call.

4

Reset to the empty state

[Caution] Caution

As usual, this object is not thread-safe.


PrevUpHomeNext