primer::result is a small structure that is meant
to be used by user code, in functions that are pushed to lua using adapt.
See adapt
reference page for extended examples.
primer::result is supposed to be the return type
in a user callback. It signals how to terminate the lua function call when
we return to lua.
There are three possible signals:
returnEnd this function call, and return some values from the stack to the caller.
yieldYield the current coroutine, which effectively "pauses" this function call, and transfers execution back to the caller. Yield is also permitted to pass some values back to the caller. (See documentation.)
errorRaise a lua error.
These are normally represented in lua C api by simply returning, or by
calling lua_yield or lua_error respectively.
In primer,
yield and error signals are represented by
structures, primer::yield
and primer::error.
return case is represented
simply by an int, as normally
in lua.
primer::result is like a variant type that
represents one of these three options.
Table 1.1. Example Usage
|
|
|
|
|---|---|---|
|
Function Prototype |
int my_func(lua_State *); |
|
|
|
return 0; |
return 0; |
return {0}; |
||
return primer::result{0}; |
||
|
|
lua_yield(L, 2); |
return primer::yield{2}; |
|
|
lua_pushstring(L, "no more foobar"); lua_error(L); |
return primer:error{"no more foobar"}; |
return and yield
both take an int, indicating
how many return values went on the stack which should be returned to the
caller.
error is indicated by a
primer::error object.
The reasons why we do it slightly differently hopefully will become clear
in the adapt section. One
advantage is that even though lua_yield
and lua_error work by executing
longjmp, returning a primer::result doesn't, so local variables in
your function get cleaned up whether lua is compiled as C or C++, and without
relying on C++ exceptions.
// Tag used by the user to indicate a yield. struct yield { int n_; }; // Helper object: Represents a return or yield signal. struct return_or_yield { int n_; bool is_return_; bool is_valid() const { return n_ >= 0; } }; // Result object class result { expected<return_or_yield> payload_; public: // Ctors (implicit for ease of use) result(int i) : payload_(return_or_yield{i, true}) {} result(yield y) : payload_(return_or_yield{y.n_, false}) {} result(error e) : payload_(e) {} // Accessor const expected<return_or_yield> & get_payload() const & { return payload_; } expected<return_or_yield> & get_payload() & { return payload_; } };