diff --git a/README.md b/README.md index 815ab4b4..c5a94632 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,9 @@ More examples are given in the examples directory. ## Presentations -"A Sun For the Moon - A Zero-Overhead Lua Abstraction using C++" -ThePhD -Lua Workshop 2016 - Mashape, San Francisco, CA +"A Sun For the Moon - A Zero-Overhead Lua Abstraction using C++" +ThePhD +Lua Workshop 2016 - Mashape, San Francisco, CA [Deck](https://github.com/ThePhD/sol2/blob/develop/docs/presentations/ThePhD%20-%20No%20Overhead%20C%20Abstraction%20-%202016.10.14.pdf) ## Creating a single header diff --git a/docs/source/api/as_table.rst b/docs/source/api/as_table.rst index cf559839..e5b58b49 100644 --- a/docs/source/api/as_table.rst +++ b/docs/source/api/as_table.rst @@ -23,4 +23,6 @@ This function serves the purpose of ensuring that an object is pushed -- if poss Note that any caveats with Lua tables apply the moment it is serialized, and the data cannot be gotten out back out in C++ as a C++ type without explicitly using the ``as_table_t`` marker for your get and conversion operations using Sol. +If you need this functionality with a member variable, use a :doc:`property on a getter function` that returns the result of ``sol::as_table``. + This marker does NOT apply to :doc:`usertypes`. \ No newline at end of file diff --git a/docs/source/api/containers.rst b/docs/source/api/containers.rst new file mode 100644 index 00000000..04649ca5 --- /dev/null +++ b/docs/source/api/containers.rst @@ -0,0 +1,72 @@ +containers +========== +for handling ``std::vector/map`` and others +------------------------------------------- + +Sol2 automatically converts containers (detected using the ``sol::is_container`` type trait, which simply looks for begin / end) to be a special kind of userdata with metatable on it. For Lua 5.2 and 5.3, this is extremely helpful as you can make typical containers behave like Lua tables without losing the actual container that they came from, as well as a small amount of indexing and other operations that behave properly given the table type. + +Here's a complete working example of it working for Lua 5.3 and Lua 5.2, and how you can retrieve out the container in all versions: + +.. code-block:: cpp + :caption: containers.cpp + + #define SOL_CHECK_ARGUMENTS + #include + + int main() { + sol::state lua; + lua.open_libraries(); + + lua.script(R"( + function f (x) + print('--- Calling f ---') + for k, v in ipairs(x) do + print(k, v) + end + end + )"); + + // Have the function we + // just defined in Lua + sol::function f = lua["f"]; + + // Set a global variable called + // "arr" to be a vector of 5 lements + lua["arr"] = std::vector{ 2, 4, 6, 8, 10 }; + + // Call it, see 5 elements + // printed out + f(lua["arr"]); + + // Mess with it in C++ + std::vector& reference_to_arr = lua["arr"]; + reference_to_arr.push_back(12); + + // Call it, see *6* elements + // printed out + f(lua["arr"]); + + return 0; +} + +Note that this will not work well in 5.1, as it has explicit table checks and does not check metamethods, even when ``pairs`` or ``ipairs`` is passed a table. In that case, you will need to use a more manual iteration scheme. + +If you have a type that has ``begin`` or ``end`` member functions but don't provide iterators, you can specialize ``sol::is_container`` to be ``std::false_type``, and that will treat the type as a regular usertype and push it as a regular userdata: + +.. code-block:: cpp + :caption: specialization.hpp + + struct not_container { + void begin() { + + } + + void end() { + + } + }; + + namespace sol { + template <> + struct is_container : std::false_type {}; + } diff --git a/docs/source/api/function.rst b/docs/source/api/function.rst index 8ca5d972..93adedab 100644 --- a/docs/source/api/function.rst +++ b/docs/source/api/function.rst @@ -3,6 +3,10 @@ function calling functions bound to Lua ------------------------------ +.. note:: + + This abstraction assumes the function runs safely. If you expect your code to have errors (e.g., you don't always have explicit control over it or are trying to debug errors), please use :doc:`sol::protected_function`. + .. code-block:: cpp class function : public reference; diff --git a/docs/source/api/state.rst b/docs/source/api/state.rst index b593d5cc..c533152e 100644 --- a/docs/source/api/state.rst +++ b/docs/source/api/state.rst @@ -82,6 +82,16 @@ Thanks to `Eric (EToreo) for the suggestion on this one`_! 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*``. It will not run: it returns a ``load_result`` proxy that can be called to actually run the code, turned into a ``sol::function``, a ``sol::protected_function``, or some other abstraction. If it is called, it will run on the object's current ``lua_State*``: it is not isolated. If you need isolation, consider creating a new state or traditional Lua sandboxing techniques. +.. code-block:: cpp + :caption: function: do_string / do_file + :name: state-do-code + + sol::protected_function_result do_string(const std::string& code); + sol::protected_function_result do_file(const std::string& filename); + +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 returns a ``protected_function_result`` proxy that can be called to actually run the code, turned into a ``sol::function``, a ``sol::protected_function``, or some other abstraction. + + .. code-block:: cpp :caption: function: global table / registry table diff --git a/docs/source/tutorial/all-the-things.rst b/docs/source/tutorial/all-the-things.rst index fa9e73ac..3695ac77 100644 --- a/docs/source/tutorial/all-the-things.rst +++ b/docs/source/tutorial/all-the-things.rst @@ -47,6 +47,10 @@ running lua code int value = lua.script("return 54"); // value == 54 +To check the success of a loading operation: + +.. code-block:: cpp + // load file without execute sol::load_result script1 = lua.load_file("path/to/luascript.lua"); script1(); //execute @@ -59,6 +63,24 @@ running lua code // value2 == 24 +To check whether a script was successfully run or not (after loading is assumed to be successful): + +.. code-block:: cpp + + // execute and return result + sol::protected_function_result result1 = lua.do_string("return 24"); + if (result1.valid()) { + int value = result1; + // value == 24 + // yay! + } + else { + // ahhh :c + } + + +There is also ``lua.do_file("path/to/luascript.lua");``. + set and get variables --------------------- diff --git a/tests.cpp b/tests.cpp index e1a92b54..faa1d352 100644 --- a/tests.cpp +++ b/tests.cpp @@ -718,77 +718,77 @@ TEST_CASE("numbers/integers", "make sure integers are detectable on most platfor } TEST_CASE("state/script-returns", "make sure script returns are done properly") { - std::string script = - R"( -local example = -{ - str = "this is a string", - num = 1234, - - func = function(self) - print(self.str) - return "fstr" - end -} - -return example; -)"; - - auto bar = [&script](sol::this_state l) { - sol::state_view lua = l; - sol::table data = lua.script(script); - - std::string str = data["str"]; - int num = data["num"]; - std::string fstr = data["func"](data); - REQUIRE(str == "this is a string"); - REQUIRE(fstr == "fstr"); - REQUIRE(num == 1234); - }; - - auto foo = [&script](int, sol::this_state l) { - sol::state_view lua = l; - sol::table data = lua.script(script); - - std::string str = data["str"]; - int num = data["num"]; - std::string fstr = data["func"](data); - REQUIRE(str == "this is a string"); - REQUIRE(fstr == "fstr"); - REQUIRE(num == 1234); - }; - - auto bar2 = [&script](sol::this_state l) { - sol::state_view lua = l; - sol::table data = lua.do_string(script); - - std::string str = data["str"]; - int num = data["num"]; - std::string fstr = data["func"](data); - REQUIRE(str == "this is a string"); - REQUIRE(fstr == "fstr"); - REQUIRE(num == 1234); - }; - - auto foo2 = [&script](int, sol::this_state l) { - sol::state_view lua = l; - sol::table data = lua.do_string(script); - - std::string str = data["str"]; - int num = data["num"]; - std::string fstr = data["func"](data); - REQUIRE(str == "this is a string"); - REQUIRE(fstr == "fstr"); - REQUIRE(num == 1234); - }; - - sol::state lua; - lua.open_libraries(); - - lua.set_function("foo", foo); - lua.set_function("foo2", foo2); - lua.set_function("bar", bar); - lua.set_function("bar2", bar2); - + std::string script = + R"( +local example = +{ + str = "this is a string", + num = 1234, + + func = function(self) + print(self.str) + return "fstr" + end +} + +return example; +)"; + + auto bar = [&script](sol::this_state l) { + sol::state_view lua = l; + sol::table data = lua.script(script); + + std::string str = data["str"]; + int num = data["num"]; + std::string fstr = data["func"](data); + REQUIRE(str == "this is a string"); + REQUIRE(fstr == "fstr"); + REQUIRE(num == 1234); + }; + + auto foo = [&script](int, sol::this_state l) { + sol::state_view lua = l; + sol::table data = lua.script(script); + + std::string str = data["str"]; + int num = data["num"]; + std::string fstr = data["func"](data); + REQUIRE(str == "this is a string"); + REQUIRE(fstr == "fstr"); + REQUIRE(num == 1234); + }; + + auto bar2 = [&script](sol::this_state l) { + sol::state_view lua = l; + sol::table data = lua.do_string(script); + + std::string str = data["str"]; + int num = data["num"]; + std::string fstr = data["func"](data); + REQUIRE(str == "this is a string"); + REQUIRE(fstr == "fstr"); + REQUIRE(num == 1234); + }; + + auto foo2 = [&script](int, sol::this_state l) { + sol::state_view lua = l; + sol::table data = lua.do_string(script); + + std::string str = data["str"]; + int num = data["num"]; + std::string fstr = data["func"](data); + REQUIRE(str == "this is a string"); + REQUIRE(fstr == "fstr"); + REQUIRE(num == 1234); + }; + + sol::state lua; + lua.open_libraries(); + + lua.set_function("foo", foo); + lua.set_function("foo2", foo2); + lua.set_function("bar", bar); + lua.set_function("bar2", bar2); + lua.script("bar() bar2() foo(1) foo2(1)"); }