state

owning and non-owning state holders for registry and globals

class state_view;

class state : state_view, std::unique_ptr<lua_State*, deleter>;

The most important class here is state_view. This structure takes a lua_State* that was already created and gives you simple, easy access to Lua’s interfaces without taking ownership. state derives from state_view, inheriting all of this functionality, but has the additional purpose of creating a fresh lua_State* and managing its lifetime for you in its constructors.

The majority of the members between state_view and sol::table are identical, with a few added for this higher-level type. Therefore, all of the examples and notes in sol::table apply here as well.

state_view is cheap to construct and creates 2 references to things in the lua_State* while it is alive: the global Lua table, and the Lua C Registry.

sol::state automatic handlers

One last thing you should understand: constructing a sol::state does a few things behind-the-scenes for you, mostly to ensure compatibility and good error handler/error handling. The function it uses to do this is set_default_state. They are as follows:

  • set a default panic handler with state_view::set_panic/lua_atpnic
  • set a default sol::protected_function handler with sol::protected_function::set_default_handler, using a sol::reference to &sol::detail::default_traceback_error_handler as the default handler function
  • set a default exception handler to &sol::detail::default_exception_handler
  • register the state as the main thread (only does something for Lua 5.1, which does not have a way to get the main thread) using sol::stack::register_main_thread(L)
  • register the LuaJIT C function exception handler with stack::luajit_exception_handler(L)

You can read up on the various panic and exception handlers on the exceptions page.

sol::state_view does none of these things for you. If you want to make sure your self-created or self-managed state has the same properties, please apply this function once to the state. Please note that it will override your panic handler and, if using LuaJIT, your LuaJIT C function handler.

Warning

It is your responsibility to make sure sol::state_view goes out of scope before you call lua_close on a pre-existing state, or before sol::state goes out of scope and its destructor gets called. Failure to do so can result in intermittent crashes because the sol::state_view has outstanding references to an already-dead lua_State*, and thusly will try to decrement the reference counts for the Lua Registry and the Global Table on a dead state. Please use { and } to create a new scope, or other lifetime techniques, when you know you are going to call lua_close so that you have a chance to specifically control the lifetime of a sol::state_view object.

enumerations

in-lua libraries
enum class lib : char {
    base,
    package,
    coroutine,
    string,
    os,
    math,
    table,
    debug,
    bit32,
    io,
    ffi,
    jit,
    count // do not use
};

This enumeration details the various base libraries that come with Lua. See the standard lua libraries for details about the various standard libraries.

members

function: open standard libraries/modules
template<typename... Args>
void open_libraries(Args&&... args);

This function takes a number of sol::lib as arguments and opens up the associated Lua core libraries.

function: script / safe_script / script_file / safe_script_file / unsafe_script / unsafe_script_file
function_result script(const string_view& code, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
protected_function_result script(const string_view& code, const environment& env, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
template <typename ErrorFunc>
protected_function_result script(const string_view& code, ErrorFunc&& on_error, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
template <typename ErrorFunc>
protected_function_result script(const string_view& code, const environment& env, ErrorFunc&& on_error, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);

function_result script_file(const std::string& filename, load_mode mode = load_mode::any);
protected_function_result script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any);
template <typename ErrorFunc>
protected_function_result script_file(const std::string& filename, ErrorFunc&& on_error, load_mode mode = load_mode::any);
template <typename ErrorFunc>
protected_function_result script_file(const std::string& filename, const environment& env, ErrorFunc&& on_error, load_mode mode = load_mode::any);

If you need safety, please use the version of these functions with safe (such as safe_script(_file)) appended in front of them. They will always check for errors and always return a sol::protected_function_result. If you explicitly do not want to check for errors and want to simply invoke lua_error in the case of errors (which will call panic), use unsafe_script(_file) versions.

These functions run the desired blob of either code that is in a string, or code that comes from a filename, on the lua_State*. It will not run isolated: any scripts or code run will affect code in the lua_State* the object uses as well (unless local is applied to a variable declaration, as specified by the Lua language). Code ran in this fashion is not isolated. If you need isolation, consider creating a new state or traditional Lua sandboxing techniques.

If your script returns a value, you can capture it from the returned sol::unsafe_function_result/sol::protected_function_result. Note that the plain versions that do not take an environment or a callback function assume that the contents internally not only loaded properly but ran to completion without errors, for the sake of simplicity and performance.

To handle errors when using the second overload, provide a callable function/object that takes a lua_State* as its first argument and a sol::protected_function_result as its second argument. sol::script_default_on_error and sol::script_pass_on_error are 2 functions provided by sol that will either generate a traceback error to return / throw (if throwing is allowed); or, pass the error on through and return it to the user (respectively). An example of having your:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <iostream>

int main () {

	std::cout << "=== safe_script usage ===" << std::endl;

	sol::state lua;
	// uses sol::script_default_on_error, which either panics or throws, 
	// depending on your configuration and compiler settings
	try {
		auto result1 = lua.safe_script("bad.code");
	}
	catch( const sol::error& e ) {
		std::cout << "an expected error has occurred: " << e.what() << std::endl;
	}
	
	// a custom handler that you write yourself
	// is only called when an error happens with loading or running the script
	auto result2 = lua.safe_script("123 bad.code", [](lua_State*, sol::protected_function_result pfr) {
		// pfr will contain things that went wrong, for either loading or executing the script
		// the user can do whatever they like here, including throw. Otherwise...
		sol::error err = pfr;
		std::cout << "An error (an expected one) occurred: " << err.what() << std::endl;

		// ... they need to return the protected_function_result
		return pfr;
	});

	std::cout << std::endl;

	return 0;
}

You can also pass a sol::environment to script/script_file to have the script have sandboxed / contained in a way inside of a state. This is useful for runnig multiple different “perspectives” or “views” on the same state, and even has fallback support. See the sol::environment documentation for more details.

function: require / require_file
sol::object require(const std::string& key, lua_CFunction open_function, bool create_global = true);
sol::object require_script(const std::string& key, const std::string& code, bool create_global = true);
sol::object require_file(const std::string& key, const std::string& file, bool create_global = true);

These functions play a role similar to luaL_requiref except that they make this functionality available for loading a one-time script or a single file. The code here checks if a module has already been loaded, and if it has not, will either load / execute the file or execute the string of code passed in. If create_global is set to true, it will also link the name key to the result returned from the open function, the code or the file. Regardless or whether a fresh load happens or not, the returned module is given as a single sol::object for you to use as you see fit.

Thanks to Eric (EToreo) for the suggestion on this one!

function: load / load_file
sol::load_result load(lua_Reader reader, void* data, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::load_result load(const string_view& code, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::load_result load_buffer(const char* buff, std::size_t buffsize, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::load_result load_file(const std::string& filename, load_mode mode = load_mode::any);

These functions load the desired blob of either code that is in a string, or code that comes from a filename, on the lua_State*. That blob will be turned into a Lua Function. It will not be run: it returns a load_result proxy that can be called to actually run the code, when you are ready. It can also be turned into a sol::function, a sol::protected_function, or some other abstraction that can serve to call the function. If it is called, it will run on the object’s current lua_State*: it is not isolated. If you need isolation, consider using sol::environment, creating a new state, or other Lua sandboxing techniques.

Finally, if you have a custom source of data, you can use the lua_Reader overloaded function alongside passing in a void* pointing to a single type that has everything you need to run it. Use that callback to provide data to the underlying Lua implementation to read data, as explained in the Lua manual.

This is a low-level function and if you do not understand the difference between loading a piece of code versus running that code, you should be using state_view::script.

function: do_string / do_file
sol::protected_function_result do_string(const string_view& code);
sol::protected_function_result do_file(const std::string& filename);
sol::protected_function_result do_string(const string_view& code, sol::environment env);
sol::protected_function_result do_file(const std::string& filename, sol::environment env);

These functions loads and performs the desired blob of either code that is in a string, or code that comes from a filename, on the lua_State*. It will run, and then return a protected_function_result proxy that can be examined for either an error or the return value. This function does not provide a callback like state_view::script does. It is a lower-level function that performs less checking and directly calls load(_file) before running the result, with the optional environment.

It is advised that, unless you have specific needs or the callback function is not to your liking, that you work directly with state_view::script.

function: global table / registry table
sol::global_table globals() const;
sol::table registry() const;

Get either the global table or the Lua registry as a sol::table, which allows you to modify either of them directly. Note that getting the global table from a state/state_view is usually unnecessary as it has all the exact same functions as a sol::table anyhow.

function: set_panic
void set_panic(lua_CFunction panic);

Overrides the panic function Lua calls when something unrecoverable or unexpected happens in the Lua VM. Must be a function of the that matches the int(lua_State*) function signature.

function: memory_used
std::size_t memory_used() const;

Returns the amount of memory used in bytes by the Lua State.

function: collect_garbage
void collect_garbage();

Attempts to run the garbage collector. Note that this is subject to the same rules as the Lua API’s collect_garbage function: memory may or may not be freed, depending on dangling references or other things, so make sure you don’t have tables or other stack-referencing items currently alive or referenced that you want to be collected.

function: make a table
sol::table create_table(int narr = 0, int nrec = 0);
template <typename Key, typename Value, typename... Args>
sol::table create_table(int narr, int nrec, Key&& key, Value&& value, Args&&... args);


template <typename... Args>
sol::table create_table_with(Args&&... args);

static sol::table create_table(lua_State* L, int narr = 0, int nrec = 0);
template <typename Key, typename Value, typename... Args>
static sol::table create_table(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args);

Creates a table. Forwards its arguments to table::create. Applies the same rules as table.set when putting the argument values into the table, including how it handles callable objects.