Luwra does not provide a standalone version of Lua nor does it isolate its features. This means that all functions and classes operate on lua_State (or the alias State). Doing this allows you to integrate Luwra however you like.
Although Luwra provides a variety of features, its main concern is efficient and safe interaction with the Lua stack.
A fundamental aspect of this is the abstract template Value. Every type which can be pushed onto or read from the stack has a specialization of it. Useful implementations are provided out of the box:
| C++ type | Pushable | Readable | Lua type |
|---|---|---|---|
| bool | yes | yes | boolean |
| signed char | yes | yes | number (integer since 5.3) |
| signed short | yes | yes | number (integer since 5.3) |
| signed int | yes | yes | number (integer since 5.3) |
| signed long int | yes | yes | number (integer since 5.3) |
| signed long long int | yes | yes | number (integer since 5.3) |
| unsigned char | yes | yes | number (integer since 5.3) |
| unsigned short | yes | yes | number (integer since 5.3) |
| unsigned int | yes | yes | number (integer since 5.3) |
| unsigned long int | yes | yes | number (integer since 5.3) |
| unsigned long long int | yes | yes | number (integer since 5.3) |
| float | yes | yes | number |
| double | yes | yes | number |
| long double | yes | yes | number |
| const char* | yes | yes | string |
| std::string | yes | yes | string |
| std::nullptr_t | yes | yes | nil |
| std::tuple<T> | yes | no | depends on the tuple contents |
| lua_CFunction | yes | no | function |
| NativeFunction<R(A...)> | no | yes | function |
| FieldVector | yes | no | table |
Note: Some numeric types have a different size than their matching Lua type - they will be truncated during push or read operations.
When pushing values onto the stack you can either use Value<T>::push or the more convenient push.
// Push an integer
luwra::push(lua, 1338);
// Push a number
luwra::push(lua, 13.37);
// Push a boolean
luwra::push(lua, false);
// Push a string
luwra::push(lua, "Hello World");
This produces the following stack layout:
| Absolute Position | Relative Position | Value |
|---|---|---|
| 1 | -4 | 1338 |
| 2 | -3 | 13.37 |
| 3 | -2 | false |
| 4 | -1 | "Hello World" |
It is possible to provide a template parameter to push to enforce pushing a specific type.
In most cases you are probably better off by letting the compiler infer the template parameter.
Simple retrieval of Lua values is done using read<T>. Consider the stack layout from the previous example. This is how you would retrieve a value from the stack.
// Retrieve the integer at position 1
int value = luwra::read<int>(lua, 1);
// Similiar with a relative index
int value = luwra::read<int>(lua, -4);
What happens when a value which you are trying to read mismatches the expected type or cannot be
converted to it? Most Value<T> specializations use Lua's luaL_check* functions to retrieve
the values from the stack. This means that no exceptions will be thrown - instead the error handling
is delegated to the Lua VM. Have a look at the
error handling documentation for more information.