diff options
Diffstat (limited to '3rdparty/sol2/docs/source/tutorial')
-rw-r--r-- | 3rdparty/sol2/docs/source/tutorial/all-the-things.rst | 606 | ||||
-rw-r--r-- | 3rdparty/sol2/docs/source/tutorial/customization.rst | 114 | ||||
-rw-r--r-- | 3rdparty/sol2/docs/source/tutorial/cxx-in-lua.rst | 138 | ||||
-rw-r--r-- | 3rdparty/sol2/docs/source/tutorial/existing.rst | 27 | ||||
-rw-r--r-- | 3rdparty/sol2/docs/source/tutorial/functions.rst | 341 | ||||
-rw-r--r-- | 3rdparty/sol2/docs/source/tutorial/getting-started.rst | 84 | ||||
-rw-r--r-- | 3rdparty/sol2/docs/source/tutorial/ownership.rst | 94 | ||||
-rw-r--r-- | 3rdparty/sol2/docs/source/tutorial/tutorial-top.rst | 21 | ||||
-rw-r--r-- | 3rdparty/sol2/docs/source/tutorial/variables.rst | 202 |
9 files changed, 1627 insertions, 0 deletions
diff --git a/3rdparty/sol2/docs/source/tutorial/all-the-things.rst b/3rdparty/sol2/docs/source/tutorial/all-the-things.rst new file mode 100644 index 00000000000..fa9e73ac6c0 --- /dev/null +++ b/3rdparty/sol2/docs/source/tutorial/all-the-things.rst @@ -0,0 +1,606 @@ +tutorial: quick 'n' dirty +========================= + +These are all the things. Use your browser's search to find things you want. + +You'll need to ``#include <sol.hpp>``/``#include "sol.hpp"`` somewhere in your code. Sol is header-only, so you don't need to compile anything. + +opening a state +--------------- + +.. code-block:: cpp + + int main (int argc, char* argv[]) { + sol::state lua; + // open some common libraries + lua.open_libraries(sol::lib::base, sol::lib::package); + lua.script( "print('bark bark bark!')" ); + } + + +sol::state on lua_State* +------------------------ + +For your system/game that already has lua, but you'd like something nice: + +.. code-block:: cpp + + int pre_existing_system( lua_State* L ) { + sol::state_view lua(L); + lua.script( "print('bark bark bark!')" ); + return 0; + } + + +running lua code +---------------- + +.. code-block:: cpp + + sol::state lua; + // load and execute from string + lua.script("a = 'test'"); + // load and execute from file + lua.script_file("path/to/luascript.lua"); + + // run a script, get the result + int value = lua.script("return 54"); + // value == 54 + + // load file without execute + sol::load_result script1 = lua.load_file("path/to/luascript.lua"); + script1(); //execute + // load string without execute + sol::load_result script2 = lua.load("a = 'test'"); + script2(); //execute + + sol::load_result script3 = lua.load("return 24"); + int value2 = script3(); // execute, get return value + // value2 == 24 + + +set and get variables +--------------------- + +You can set/get everything. + +.. code-block:: cpp + + sol::lua_state lua; + + lua.open_libraries(sol::lib::base); + + // integer types + lua.set("number", 24); + + // floating point numbers + lua["number2"] = 24.5; + + // string types + lua["important_string"] = "woof woof"; + + // non-recognized types is stored as userdata + // is callable, therefore gets stored as a function + lua["a_function"] = [](){ return 100; }; + + // make a table + lua["some_table"] = lua.create_table_wth("value", 24); + + +Equivalent to loading a lua file with: + +.. code-block:: lua + + number = 24 + number2 = 24.5 + important_string = "woof woof" + a_function = function () return 100 end + some_table = { value = 24 } + +Retrieve these variables using this syntax: + +.. code-block:: cpp + + // implicit conversion + int number = lua["number"]; + + // explicit get + auto number2 = lua.get<double>("number2"); + + // strings too + std::string important_string = lua["important_string"]; + + // dig into a table + int value = lua["value"]["value"]; + + // get a function + sol::function a_function = lua["a_function"]; + int value_is_100 = a_function(); + + // get a std::function + std::function<int()> a_std_function = lua["a_function"]; + int value_is_still_100 = a_std_function(); + +Retrieve Lua types using ``object`` and other ``sol::`` types. + +.. code-block:: cpp + + sol::state lua; + + // ... everything from before + + sol::object number_obj = lua.get<sol::object>( "number" ); + // sol::type::number + sol::type t1 = number_obj.get_type(); + + sol::object function_obj = lua[ "a_function" ]; + // sol::type::function + sol::type t2 = function_obj.get_type(); + bool is_it_really = function_obj.is<std::function<int()>(); // true + + // will not contain data + sol::optional<int> check_for_me = lua["a_function"]; + + +You can erase things by setting it to ``nullptr`` or ``sol::nil``. + +.. code-block:: cpp + + sol::state lua; + + lua.script("exists = 250"); + + int first_try = lua.get_or<int>( 322 ); + // first_try == 250 + + lua.set("exists", sol::nil); + + int second_try = lua.get_or<int>( 322 ); + // second_try == 322 + + +Note that if its a :doc:`userdata/usertype<../api/usertype>` for a C++ type, the destructor will run only when the garbage collector deems it appropriate to destroy the memory. If you are relying on the destructor being run when its set to ``sol::nil``, you're probably committing a mistake. + +tables +------ + +:doc:`sol::state<../api/state>` is a table too. + +.. code-block:: cpp + + sol::state lua; + + // Raw string literal for easy multiline + lua.script( R"( + abc = { [0] = 24 } + def = { + ghi = { + bark = 50, + woof = abc + } + } + )" + ); + + sol::table abc = lua["abc"]; + sol::table def = lua["def"]; + sol::table ghi = lua["def"]["ghi"]; + + int bark1 = def["ghi"]["bark"]; + int bark2 = lua["def"]["ghi"]["bark"]; + // bark1 == bark2 == 50 + + int abcval1 = abc[0]; + int abcval2 = ghi["woof"][0]; + // abcval1 == abcval2 == 24 + +If you're going deep, be safe: + +.. code-block:: cpp + + sol::state lua; + + sol::optional<int> will_not_error = lua["abc"]["DOESNOTEXIST"]["ghi"]; + // will_not_error == sol::nullopt + int will_not_error2 = lua["abc"]["def"]["ghi"]["jklm"].get_or<int>(25); + // is 25 + + // if you don't go safe, + // will throw (or do at_panic if no exceptions) + int aaaahhh = lua["abc"]["hope_u_liek_crash"]; + + +make tables +----------- + +Make some: + +.. code-block:: cpp + + sol::state lua; + + lua["abc"] = lua.create_table_with( + 0, 24 + ); + + lua.create_named_table("def", + "ghi", lua.create_table_with( + "bark", 50, + // can reference other existing stuff too + "woof", lua["abc"] + ) + ); + +Equivalent Lua code: + +.. code-block:: lua + + abc = { [0] = 24 } + def = { + ghi = { + bark = 50, + woof = abc + } + } + + +You can put anything you want in tables as values or keys, including strings, numbers, functions, other tables. + +Note that this idea that things can be nested is important and will help later when you get into :ref:`namespacing<namespacing>`. + + +functions +--------- + +They're great. Use them: + +.. code-block:: cpp + + sol::state lua; + + lua.script("function f (a, b, c, d) return 1 end"); + lua.script("function g (a, b) return a + b end"); + + // fixed signature std::function<...> + std::function<int(int, double, int, std::string)> stdfx = lua["f"]; + // sol::function is often easier: + // takes a variable number/types of arguments... + sol::function fx = lua["f"]; + + int is_one = stdfx(1, 34.5, 3, "bark"); + int is_also_one = fx(1, "boop", 3, "bark"); + + // call through operator[] + int is_three = lua["g"](1, 2); + // is_three == 3 + double is_4_8 = lua["g"](2.4, 2.4); + // is_4_8 == 4.8 + +If you need to protect against errors and parser problems and you're not ready to deal with Lua's `longjmp` problems (if you compiled with C), use :doc:`sol::protected_function<../api/protected_function>`. + +You can bind member variables as functions too, as well as all KINDS of function-like things: + +.. code-block:: cpp + + void some_function () { + std::cout << "some function!" << std::endl; + } + + void some_other_function () { + std::cout << "some other function!" << std::endl; + } + + struct some_class { + int variable = 30; + + double member_function () { + return 24.5; + } + }; + + sol::state lua; + lua.open_libraries(sol::lib::base); + + // put an instance of "some_class" into lua + // (we'll go into more detail about this later + // just know here that it works and is + // put into lua as a userdata + lua.set("sc", some_class()); + + // binds a plain function + lua["f1"] = some_function; + lua.set_function("f2", &some_other_function); + + // binds just the member function + lua["m1"] = &some_class::member_function; + + // binds the class to the type + lua.set_function("m2", &some_class::member_function, some_class{}); + + // binds just the member variable as a function + lua["v1"] = &some_class::variable; + + // binds class with member variable as function + lua.set_function("v2", &some_class::variable, some_class{}); + +The lua code to call these things is: + +.. code-block:: lua + + f1() -- some function! + f2() -- some other function! + + -- need class instance if you don't bind it with the function + print(m1(sc)) -- 24.5 + -- does not need class instance: was bound to lua with one + print(m2()) -- 24.5 + + -- need class instance if you + -- don't bind it with the function + print(v1(sc)) -- 30 + -- does not need class instance: + -- it was bound with one + print(v2()) -- 30 + + -- can set, still + -- requires instance + v1(sc, 212) + -- can set, does not need + -- class instance: was bound with one + v2(254) + + print(v1(sc)) -- 212 + print(v2()) -- 254 + +Can use ``sol::readonly( &some_class::variable )`` to make a variable readonly and error if someone tries to write to it. + + +self call +--------- + +You can pass the 'self' argument through C++ to emulate 'member function' calls in Lua. + +.. code-block:: cpp + + sol::state lua; + + lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::table); + + // a small script using 'self' syntax + lua.script(R"( + some_table = { some_val = 100 } + + function some_table:add_to_some_val(value) + self.some_val = self.some_val + value + end + + function print_some_val() + print("some_table.some_val = " .. some_table.some_val) + end + )"); + + // do some printing + lua["print_some_val"](); + // 100 + + sol::table self = lua["some_table"]; + self["add_to_some_val"](self, 10); + lua["print_some_val"](); + + + +multiple returns from lua +------------------------- + +.. code-block:: cpp + + sol::state lua; + + lua.script("function f (a, b, c) return a, b, c end"); + + std::tuple<int, int, int> result; + result = lua["f"](100, 200, 300); + // result == { 100, 200, 300 } + int a, int b; + std::string c; + sol::tie( a, b, c ) = lua["f"](100, 200, "bark"); + // a == 100 + // b == 200 + // c == "bark" + + +multiple returns to lua +----------------------- + +.. code-block:: cpp + + sol::state lua; + + lua["f"] = [](int a, int b, sol::object c) { + // sol::object can be anything here: just pass it through + return std::make_tuple( a, b, c ); + }; + + std::tuple<int, int, int> result = lua["f"](100, 200, 300); + // result == { 100, 200, 300 } + + std::tuple<int, int, std::string> result2; + result2 = lua["f"](100, 200, "BARK BARK BARK!") + // result2 == { 100, 200, "BARK BARK BARK!" } + + int a, int b; + std::string c; + sol::tie( a, b, c ) = lua["f"](100, 200, "bark"); + // a == 100 + // b == 200 + // c == "bark" + + +C++ classes from C++ +-------------------- + +Everything that is not a: + + * primitive type: ``bool``, ``char/short/int/long/long long``, ``float/double`` + * string type: ``std::string``, ``const char*`` + * function type: function pointers, ``lua_CFunction``, ``std::function``, :doc:`sol::function/sol::protected_function<../api/function>`, :doc:`sol::coroutine<../api/coroutine>`, member variable, member function + * designated sol type: :doc:`sol::table<../api/table>`, :doc:`sol::thread<../api/thread>`, :doc:`sol::error<../api/error>`, :doc:`sol::object<../api/object>` + * transparent argument type: :doc:`sol::variadic_arg<../api/variadic_args>`, :doc:`sol::this_state<../api/this_state>` + * usertype<T> class: :doc:`sol::usertype<../api/usertype>` + +Is set as a :doc:`userdata + usertype<../api/usertype>`. + +.. code-block:: cpp + + struct Doge { + int tailwag = 50; + } + + Doge dog{}; + + // Copy into lua: destroyed by Lua VM during garbage collection + lua["dog"] = dog; + // OR: move semantics - will call move constructor if present instead + // Again, owned by Lua + lua["dog"] = std::move( dog ); + lua["dog"] = Doge{}; + lua["dog"] = std::make_unique<Doge>(); + lua["dog"] = std::make_shared<Doge>(); + // Identical to above + + Doge dog2{}; + + lua.set("dog", dog2); + lua.set("dog", std::move(dog2)); + lua.set("dog", Doge{}); + lua.set("dog", std::unique_ptr<Doge>(new Doge())); + lua.set("dog", std::shared_ptr<Doge>(new Doge())); + +``std::unique_ptr``/``std::shared_ptr``'s reference counts / deleters will :doc:`be respected<../api/unique_usertype_traits>`. If you want it to refer to something, whose memory you know won't die in C++, do the following: + +.. code-block:: cpp + + struct Doge { + int tailwag = 50; + } + + sol::state lua; + lua.open_libraries(sol::lib::base); + + Doge dog{}; // Kept alive somehow + + // Later... + // The following stores a reference, and does not copy/move + // lifetime is same as dog in C++ + // (access after it is destroyed is bad) + lua["dog"] = &dog; + // Same as above: respects std::reference_wrapper + lua["dog"] = std::ref(dog); + // These two are identical to above + lua.set( "dog", &dog ); + lua.set( "dog", std::ref( dog ) ); + +Get userdata in the same way as everything else: + +.. code-block:: cpp + + struct Doge { + int tailwag = 50; + } + + sol::state lua; + lua.open_libraries(sol::lib::base); + + Doge& dog = lua["dog"]; // References Lua memory + Doge* dog_pointer = lua["dog"]; // References Lua memory + Doge dog_copy = lua["dog"]; // Copies, will not affect lua + +Note that you can change the data of usertype variables and it will affect things in lua if you get a pointer or a reference from Sol: + +.. code-block:: cpp + + struct Doge { + int tailwag = 50; + } + + sol::state lua; + lua.open_libraries(sol::lib::base); + + Doge& dog = lua["dog"]; // References Lua memory + Doge* dog_pointer = lua["dog"]; // References Lua memory + Doge dog_copy = lua["dog"]; // Copies, will not affect lua + + dog_copy.tailwag = 525; + // Still 50 + lua.script("assert(dog.tailwag == 50)"); + + dog.tailwag = 100; + // Now 100 + lua.script("assert(dog.tailwag == 100)"); + + +C++ classes put into Lua +------------------------ + +See this :doc:`section here<cxx-in-lua>` and after perhaps see if :doc:`simple usertypes suit your needs<../api/simple_usertype>`. Also check out some `a basic example`_, `special functions`_ and `initializers`_, + + +.. _namespacing: + +namespacing +----------- + +You can emulate namespacing by having a table and giving it the namespace names you want before registering enums or usertypes: + +.. code-block:: cpp + + struct my_class { + int b = 24; + + int f () const { + return 24; + } + + void g () { + ++b; + } + }; + + sol::state lua; + lua.open_libraries(); + + // set up table + sol::table bark = lua.create_named_table("bark"); + + bark.new_usertype<my_class>( "my_class", + "f", &my_class::f, + "g", &my_class::g + ); // the usual + + // 'bark' namespace + lua.script("obj = bark.my_class.new()" ); + lua.script("obj:g()"); + my_class& obj = lua["obj"]; + // obj.b == 25 + + +This technique can be used to register namespace-like functions and classes. It can be as deep as you want. Just make a table and name it appropriately, in either Lua script or using the equivalent Sol code. As long as the table FIRST exists (e.g., make it using a script or with one of Sol's methods or whatever you like), you can put anything you want specifically into that table using :doc:`sol::table's<../api/table>` abstractions. + +advanced +-------- + +Some more advanced things you can do/read about: + * :doc:`metatable manipulations<../api/metatable_key>` allow a user to change how indexing, function calls, and other things work on a single type. + * :doc:`ownership semantics<ownership>` are described for how lua deals with (raw) pointers. + * :doc:`stack manipulation<../api/stack>` to safely play with the stack. You can also define customization points for ``stack::get``/``stack::check``/``stack::push`` for your type. + * :doc:`make_reference/make_object convenience function<../api/make_reference>` to get the same benefits and conveniences as the low-level stack API but put into objects you can specify. + * :doc:`stack references<../api/stack_reference>` to have zero-overhead Sol abstractions while not copying to the Lua registry. + * :doc:`unique usertype traits<../api/unique_usertype_traits>` allows you to specialize handle/RAII types from other frameworks, like boost, and Unreal, to work with Sol. + * :doc:`variadic arguments<../api/variadic_args>` in functions with ``sol::variadic_args``. + * :doc:`this_state<../api/this_state>` to get the current ``lua_State*``. + * :doc:`resolve<../api/resolve>` overloads in case you have overloaded functions; a cleaner casting utility. + +.. _a basic example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype.cpp +.. _special functions: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_special_functions.cpp +.. _initializers: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_initializers.cpp + diff --git a/3rdparty/sol2/docs/source/tutorial/customization.rst b/3rdparty/sol2/docs/source/tutorial/customization.rst new file mode 100644 index 00000000000..31fcad46568 --- /dev/null +++ b/3rdparty/sol2/docs/source/tutorial/customization.rst @@ -0,0 +1,114 @@ +adding your own types +===================== + +Sometimes, overriding Sol to make it handle certain ``struct``'s and ``class``'es as something other than just userdata is desirable. The way to do this is to take advantage of the 4 customization points for Sol. These are ``sol::lua_size<T>``, ``sol::stack::pusher<T, C>``, ``sol::stack::getter<T, C>``, ``sol::stack::checker<T, sol::type t, C>``. + +These are template class/structs, so you'll override them using a technique C++ calls *class/struct specialization*. Below is an example of a struct that gets broken apart into 2 pieces when going in the C++ --> Lua direction, and then pulled back into a struct when going in the Lua --> C++: + +.. code-block:: cpp + :caption: two_things.hpp + :name: customization-overriding + + #include <sol.hpp> + + struct two_things { + int a; + bool b; + }; + + namespace sol { + + // First, the expected size + // Specialization of a struct + // We expect 2, so use 2 + template <> + struct lua_size<two_things> : std::integral_constant<int, 2> {}; + + // Now, specialize various stack structures + namespace stack { + + template <> + struct checker<two_things> { + template <typename Handler> + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + // indices can be negative to count backwards from the top of the stack, + // rather than the bottom up + // to deal with this, we adjust the index to + // its absolute position using the lua_absindex function + int absolute_index = lua_absindex(L, index); + // Check first and second second index for being the proper types + bool success = stack::check<int>(L, absolute_index - 1, handler) + && stack::check<bool>(L, absolute_index, handler); + tracking.use(2); + return success; + } + }; + + template <> + struct getter<two_things> { + static two_things get(lua_State* L, int index, record& tracking) { + int absolute_index = lua_absindex(L, index); + // Get the first element + int a = stack::get<int>(L, absolute_index - 1); + // Get the second element, + // in the +1 position from the first + bool b = stack::get<bool>(L, absolute_index); + // we use 2 slots, each of the previous takes 1 + tracking.use(2); + return two_things{ a, b }; + } + }; + + template <> + struct pusher<two_things> { + static int push(lua_State* L, const two_things& things) { + int amount = stack::push(L, things.a); + // amount will be 1: int pushes 1 item + amount += stack::push(L, things.b); + // amount 2 now, since bool pushes a single item + // Return 2 things + return amount; + } + }; + + } + } + + +This is the base formula that you can follow to extend to your own classes. Using it in the rest of the library should then be seamless: + +.. code-block:: cpp + :caption: customization: using it + :name: customization-using + + #include <sol.hpp> + #include <two_things.hpp> + + int main () { + + sol::state lua; + + // Create a pass-through style of function + lua.script("function f ( a, b ) return a, b end"); + + // get the function out of Lua + sol::function f = lua["f"]; + + two_things things = f(two_things{24, true}); + // things.a == 24 + // things.b == true + + return 0; + } + + +And that's it! + +A few things of note about the implementation: First, there's an auxiliary parameter of type :doc:`sol::stack::record<../api/stack>` for the getters and checkers. This keeps track of what the last complete operation performed. Since we retrieved 2 members, we use ``tracking.use(2);`` to indicate that we used 2 stack positions (one for ``bool``, one for ``int``). The second thing to note here is that we made sure to use the ``index`` parameter, and then proceeded to add 1 to it for the next one. + +You can make something pushable into Lua, but not get-able in the same way if you only specialize one part of the system. If you need to retrieve it (as a return using one or multiple values from Lua), you should specialize the ``sol::stack::getter`` template class and the ``sol::stack::checker`` template class. If you need to push it into Lua at some point, then you'll want to specialize the ``sol::stack::pusher`` template class. The ``sol::lua_size`` template class trait needs to be specialized for both cases, unless it only pushes 1 item, in which case the default implementation will assume 1. + + +In general, this is fine since most getters/checkers only use 1 stack point. But, if you're doing more complex nested classes, it would be useful to use ``tracking.last`` to understand how many stack indices the last getter/checker operation did and increment it by ``index + tracking.last`` after using a ``stack::check<..>( L, index, tracking)`` call. + +You can read more about the structs themselves :ref:`over on the API page for stack<extension_points>`, and if there's something that goes wrong or you have anymore questions, please feel free to drop a line on the Github Issues page or send an e-mail!
\ No newline at end of file diff --git a/3rdparty/sol2/docs/source/tutorial/cxx-in-lua.rst b/3rdparty/sol2/docs/source/tutorial/cxx-in-lua.rst new file mode 100644 index 00000000000..dac47dfb228 --- /dev/null +++ b/3rdparty/sol2/docs/source/tutorial/cxx-in-lua.rst @@ -0,0 +1,138 @@ +C++ in Lua +========== + +Using user defined types ("usertype"s, or just "udt"s) is simple with Sol. If you don't call any member variables or functions, then you don't even have to 'register' the usertype at all: just pass it through. But if you want variables and functions on your usertype inside of Lua, you need to register it. We're going to give a short example here that includes a bunch of information on how to work with things. + +Take this ``player`` struct in C++ in a header file: + +.. code-block:: cpp + :caption: test_player.hpp + + struct player { + public: + int bullets; + int speed; + + player() + : player(3, 100) { + + } + + player(int ammo) + : player(ammo, 100) { + + } + + player(int ammo, int hitpoints) + : bullets(ammo), hp(hitpoints) { + + } + + void boost () { + speed += 10; + } + + bool shoot () { + if (bullets < 1) + return false; + --bullets; + return true; + } + + void set_hp(int value) { + hp = value; + } + + int get_hp() const { + return hp; + } + + private: + int hp; + }; + + +It's a fairly minimal class, but we don't want to have to rewrite this with metatables in Lua. We want this to be part of Lua easily. The following is the Lua code that we'd like to have work properly: + +.. code-block:: lua + :caption: player_script.lua + + -- call single argument integer constructor + p1 = player.new(2) + + -- p2 is still here from being + -- set with lua["p2"] = player(0); + -- in cpp file + local p2shoots = p2:shoot() + assert(not p2shoots) + -- had 0 ammo + + -- set variable property setter + p1.hp = 545; + -- get variable through property getter + print(p1.hp); + + local did_shoot_1 = p1:shoot() + print(did_shoot_1) + print(p1.bullets) + local did_shoot_2 = p1:shoot() + print(did_shoot_2) + print(p1.bullets) + local did_shoot_3 = p1:shoot() + print(did_shoot_3) + + -- can read + print(p1.bullets) + -- would error: is a readonly variable, cannot write + -- p1.bullets = 20 + + p1:boost() + +To do this, you bind things using the ``new_usertype`` and ``set_usertype`` methods as shown below. These methods are on both :doc:`table<../api/table>` and :doc:`state(_view)<../api/state>`, but we're going to just use it on ``state``: + +.. code-block:: cpp + :caption: player_script.cpp + + #include <sol.hpp> + + int main () { + sol::state lua; + + // note that you can set a + // userdata before you register a usertype, + // and it will still carry + // the right metatable if you register it later + + // set a variable "p2" of type "player" with 0 ammo + lua["p2"] = player(0); + + // make usertype metatable + lua.new_usertype<player>( "player", + + // 3 constructors + sol::constructors<sol::types<>, sol::types<int>, sol::types<int, int>>(), + + // typical member function that returns a variable + "shoot", &player::shoot, + // typical member function + "boost", &player::boost, + + // gets or set the value using member variable syntax + "hp", sol::property(&player::get_hp, &player::set_hp), + + // read and write variable + "speed", &player::speed, + // can only read from, not write to + "bullets", sol::readonly( &player::bullets ) + ); + + lua.script_file("player_script.lua"); + } + +That script should run fine now, and you can observe and play around with the values. Even more stuff :doc:`you can do<../api/usertype>` is described elsewhere, like initializer functions (private constructors / destructors support), "static" functions callable with ``name.my_function( ... )``, and overloaded member functions. You can even bind global variables (even by reference with ``std::ref``) with ``sol::var``. There's a lot to try out! + +This is a powerful way to allow reuse of C++ code from Lua beyond just registering functions, and should get you on your way to having more complex classes and data structures! In the case that you need more customization than just usertypes, however, you can customize Sol to behave more fit to your desires by using the desired :doc:`customization and extension structures<customization>`. + +You can check out this code and more complicated code at the `examples directory`_ by looking at the ``usertype_``-prefixed examples. + +.. _examples directory: https://github.com/ThePhD/sol2/tree/develop/examples
\ No newline at end of file diff --git a/3rdparty/sol2/docs/source/tutorial/existing.rst b/3rdparty/sol2/docs/source/tutorial/existing.rst new file mode 100644 index 00000000000..89a83f8078d --- /dev/null +++ b/3rdparty/sol2/docs/source/tutorial/existing.rst @@ -0,0 +1,27 @@ +integrating into existing code +============================== + +If you're already using lua and you just want to use ``sol`` in some places, you can use ``state_view``: + +.. code-block:: cpp + :linenos: + :caption: using state_view + :name: state-view-snippet + + void something_in_my_system (lua_State* L) { + // start using Sol with a pre-existing system + sol::state_view lua(L); // non-owning + + lua.script("print('bark bark bark!')"); + + sol::table expected_table(L); // get the table off the top of the stack + // start using it... + } + +:doc:`sol::state_view<../api/state>` is exactly like ``sol::state``, but it doesn't manage the lifetime of a ``lua_State*``. Therefore, you get all the goodies that come with a ``sol::state`` without any of the ownership implications. Sol has no initialization components that need to deliberately remain alive for the duration of the program. It's entirely self-containing and uses lua's garbage collectors and various implementation techniques to require no state C++-side. After you do that, all of the power of `Sol` is available to you, and then some! + +You may also want to call ``require`` and supply a string of a script file or something that returns an object that you set equal to something in C++. For that, you can use the :ref:`require functionality<state-require-function>`. + +Remember that Sol can be as lightweight as you want it: almost all of Sol's types take the ``lua_State*`` argument and then a second ``int index`` stack index argument, meaning you can use :doc:`tables<../api/table>`, :doc:`lua functions<../api/function>`, :doc:`coroutines<../api/coroutine>`, and other reference-derived objects that expose the proper constructor for your use. You can also set :doc:`usertypes<../api/usertype>` and other things you need without changing your entire architecture. + +Note that you can also make non-standard pointer and reference types with custom reference counting and such also play nice with the system. See :doc:`unique_usertype_traits\<T><../api/unique_usertype_traits>` to see how! Custom types is also mentioned in the :doc:`customization tutorial<customization>`.
\ No newline at end of file diff --git a/3rdparty/sol2/docs/source/tutorial/functions.rst b/3rdparty/sol2/docs/source/tutorial/functions.rst new file mode 100644 index 00000000000..2b2f0e3ba61 --- /dev/null +++ b/3rdparty/sol2/docs/source/tutorial/functions.rst @@ -0,0 +1,341 @@ +functions and You +================= + +Sol can register all kinds of functions. Many are shown in the :doc:`quick 'n' dirty<all-the-things>`, but here we will discuss many of the additional ways you can register functions into a sol-wrapped Lua system. + +Setting a new function +---------------------- + +Given a C++ function, you can drop it into Sol in several equivalent ways, working similar to how :ref:`setting variables<writing-main-cpp>` works: + +.. code-block:: cpp + :linenos: + :caption: Registering C++ functions + :name: writing-functions + + #include <sol.hpp> + + std::string my_function( int a, std::string b ) { + // Create a string with the letter 'D' "a" times, + // append it to 'b' + return b + std::string( 'D', a ); + } + + int main () { + + sol::state lua; + + lua["my_func"] = my_function; // way 1 + lua.set("my_func", my_function); // way 2 + lua.set_function("my_func", my_function); // way 3 + + // This function is now accessible as 'my_func' in + // lua scripts / code run on this state: + lua.script("some_str = my_func(1, "Da"); + + // Read out the global variable we stored in 'some_str' in the + // quick lua code we just executed + std::string some_str = lua["some_str"]; + // some_str == "DaD" + } + +The same code works with all sorts of functions, from member function/variable pointers you have on a class as well as lambdas: + +.. code-block:: cpp + :linenos: + :caption: Registering C++ member functions + :name: writing-member-functions + + struct my_class { + int a = 0; + + my_class(int x) : a(x) { + + } + + int func() { + ++a; // increment a by 1 + return a; + } + }; + + int main () { + + sol::state lua; + + // Here, we are binding the member function and a class instance: it will call the function on + // the given class instance + lua.set_function("my_class_func", &my_class::func, my_class()); + + // We do not pass a class instance here: + // the function will need you to pass an instance of "my_class" to it + // in lua to work, as shown below + lua.set_function("my_class_func_2", &my_class::func); + + // With a pre-bound instance: + lua.script(R"( + first_value = my_class_func() + second_value = my_class_func() + )"); + // first_value == 1 + // second_value == 2 + + // With no bound instance: + lua.set("obj", my_class(24)); + // Calls "func" on the class instance + // referenced by "obj" in Lua + lua.script(R"( + third_value = my_class_func_2(obj) + fourth_value = my_class_func_2(obj) + )"); + // first_value == 25 + // second_value == 26 + } + +Member class functions and member class variables will both be turned into functions when set in this manner. You can get intuitive variable with the ``obj.a = value`` access after this section when you learn about :doc:`usertypes to have C++ in Lua<cxx-in-lua>`, but for now we're just dealing with functions! + + +Another question a lot of people have is about function templates. Function templates -- member functions or free functions -- cannot be registered because they do not exist until you instantiate them in C++. Therefore, given a templated function such as: + +.. code-block:: cpp + :linenos: + :caption: A C++ templated function + :name: writing-templated-functions-the-func + + template <typename A, typename B> + auto my_add( A a, B b ) { + return a + b; + } + + +You must specify all the template arguments in order to bind and use it, like so: + +.. code-block:: cpp + :linenos: + :caption: Registering function template instantiations + :name: writing-templated-functions + + + int main () { + + sol::state lua; + + // adds 2 integers + lua["my_int_add"] = my_add<int, int>; + + // concatenates 2 strings + lua["my_string_combine"] = my_add<std::string, std::string>; + + lua.script("my_num = my_int_add(1, 2)"); + int my_num = lua["my_num"]; + // my_num == 3 + + lua.script("my_str = my_string_combine('bark bark', ' woof woof')"); + std::string my_str = lua["my_str"]; + // my_str == "bark bark woof woof" + } + +Notice here that we bind two separate functions. What if we wanted to bind only one function, but have it behave differently based on what arguments it is called with? This is called Overloading, and it can be done with :doc:`sol::overload<../api/overload>` like so: + +.. code-block:: cpp + :linenos: + :caption: Registering C++ function template instantiations + :name: writing-templated-functions-overloaded + + + int main () { + + sol::state lua; + + // adds 2 integers + lua["my_combine"] = sol::overload( my_add<int, int>, my_add<std::string, std::string> ); + + lua.script("my_num = my_combine(1, 2)"); + lua.script("my_str = my_combine('bark bark', ' woof woof')"); + int my_num = lua["my_num"]; + std::string my_str = lua["my_str"]; + // my_num == 3 + // my_str == "bark bark woof woof" + } + +This is useful for functions which can take multiple types and need to behave differently based on those types. You can set as many overloads as you want, and they can be of many different types. + +.. note:: + + Function object ``obj`` -- a struct with a ``return_type operator()( ... )`` member defined on them, like all C++ lambdas -- are not interpreted as functions when you use ``set`` for ``mytable.set( key, value )``. This only happens automagically with ``mytable[key] = obj``. To be explicit about wanting a struct to be interpreted as a function, use ``mytable.set_function( key, func_value );``. You can be explicit about wanting a function as well by using the :doc:`sol::as_function<../api/as_function>` call. + + +Getting a function from Lua +--------------------------- + +There are 2 ways to get a function from Lua. One is with :doc:`sol::function<../api/function>` and the other is a more advanced wrapper with :doc:`sol::protected_function<../api/protected_function>`. Use them to retrieve callables from Lua and call the underlying function, in two ways: + +.. code-block:: cpp + :linenos: + :caption: Retrieving a sol::function + :name: reading-functions + + int main () { + + sol::state lua; + + lua.script(R"( + function f (a) + return a + 5 + end + )"); + + // Get and immediately call + int x = lua["f"](30); + // x == 35 + + // Store it into a variable first, then call + sol::function f = lua["f"]; + int y = f(20); + // y == 25 + } + +You can get anything that's a callable in Lua, including C++ functions you bind using ``set_function`` or similar. ``sol::protected_function`` behaves similarly to ``sol::function``, but has a :ref:`error_handler<protected-function-error-handler>` variable you can set to a Lua function. This catches all errors and runs them through the error-handling function: + + +.. code-block:: cpp + :linenos: + :caption: Retrieving a sol::protected_function + :name: reading-protected-functions + + int main () { + sol::state lua; + + lua.script(R"( + function handler (message) + return "Handled this message: " .. message + end + + function f (a) + if a < 0 then + error("negative number detected") + end + return a + 5 + end + )"); + + sol::protected_function f = lua["f"]; + f.error_handler = lua["handler"]; + + sol::protected_function_result result = f(-500); + if (result.valid()) { + // Call succeeded + int x = result; + } + else { + // Call failed + sol::error err = result; + std::string what = err.what(); + // 'what' Should read + // "Handled this message: negative number detected" + } + } + + +Multiple returns to and from Lua +-------------------------------- + +You can return multiple items to and from Lua using ``std::tuple``/``std::pair`` classes provided by C++. These enable you to also use :doc:`sol::tie<../api/tie>` to set return values into pre-declared items. To recieve multiple returns, just ask for a ``std::tuple`` type from the result of a function's computation, or ``sol::tie`` a bunch of pre-declared variables together and set the result equal to that: + +.. code-block:: cpp + :linenos: + :caption: Multiple returns from Lua + :name: multi-return-lua-functions + + int main () { + sol::state lua; + + lua.script("function f (a, b, c) return a, b, c end"); + + std::tuple<int, int, int> result; + result = lua["f"](1, 2, 3); + // result == { 1, 2, 3 } + int a, int b; + std::string c; + sol::tie( a, b, c ) = lua["f"](1, 2, "bark"); + // a == 1 + // b == 2 + // c == "bark" + } + +You can also return mutiple items yourself from a C++-bound function. Here, we're going to bind a C++ lambda into Lua, and then call it through Lua and get a ``std::tuple`` out on the other side: + +.. code-block:: cpp + :linenos: + :caption: Multiple returns into Lua + :name: multi-return-cxx-functions + + int main () { + sol::state lua; + + lua["f"] = [](int a, int b, sol::object c) { + // sol::object can be anything here: just pass it through + return std::make_tuple( a, b, c ); + }; + + std::tuple<int, int, int> result = lua["f"](1, 2, 3); + // result == { 1, 2, 3 } + + std::tuple<int, int, std::string> result2; + result2 = lua["f"](1, 2, "Arf?") + // result2 == { 1, 2, "Arf?" } + + int a, int b; + std::string c; + sol::tie( a, b, c ) = lua["f"](1, 2, "meow"); + // a == 1 + // b == 2 + // c == "meow" + } + + +Note here that we use :doc:`sol::object<../api/object>` to transport through "any value" that can come from Lua. You can also use ``sol::make_object`` to create an object from some value, so that it can be returned into Lua as well. + + +Any return to and from Lua +-------------------------- + +It was hinted at in the previous code example, but ``sol::object`` is a good way to pass "any type" back into Lua (while we all wait for ``std::variant<...>`` to get implemented and shipped by C++ compiler/library implementers). + +It can be used like so, inconjunction with ``sol::this_state``: + +.. code-block:: cpp + :linenos: + :caption: Return anything into Lua + :name: object-return-cxx-functions + + sol::object fancy_func (sol::object a, sol::object b, sol::this_state s) { + sol::state_view lua(s); + if (a.is<int>() && b.is<int>()) { + return sol::make_object(lua, a.as<int>() + b.as<int>()); + } + else if (a.is<bool>()) { + bool do_triple = a.as<bool>(); + return sol::make_object(lua, b.as<double>() * ( do_triple ? 3 : 1 ) ); + } + return sol::make_object(lua, sol::nil); + } + + int main () { + sol::state lua; + + lua["f"] = fancy_func; + + int result = lua["f"](1, 2); + // result == 3 + double result2 = lua["f"](false, 2.5); + // result2 == 2.5 + + // call in Lua, get result + lua.script("result3 = f(true, 5.5)"); + double result3 = lua["result3"]; + // result3 == 16.5 + } + + +This covers almost everything you need to know about Functions and how they interact with Sol. For some advanced tricks and neat things, check out :doc:`sol::this_state<../api/this_state>` and :doc:`sol::variadic_args<../api/variadic_args>`. The next stop in this tutorial is about :doc:`C++ types (usertypes) in Lua<cxx-in-lua>`!
\ No newline at end of file diff --git a/3rdparty/sol2/docs/source/tutorial/getting-started.rst b/3rdparty/sol2/docs/source/tutorial/getting-started.rst new file mode 100644 index 00000000000..fd83e4fcb93 --- /dev/null +++ b/3rdparty/sol2/docs/source/tutorial/getting-started.rst @@ -0,0 +1,84 @@ +getting started +=============== + +Let's get you going with Sol! To start, you'll need to use a lua distribution of some sort. Sol doesn't provide that: it only wraps the API that comes with it, so you can pick whatever distribution you like for your application. There are lots, but the two popular ones are `vanilla Lua`_ and speedy `LuaJIT`_ . We recommend vanilla Lua if you're getting started, LuaJIT if you need speed and can handle some caveats: the interface for Sol doesn't change no matter what Lua version you're using. + +If you need help getting or building Lua, check out the `Lua page on getting started`_. Note that for Visual Studio, one can simply download the sources, include all the Lua library files in that project, and then build for debug/release, x86/x64/ARM rather easily and with minimal interference. Just make sure to adjust the Project Property page to build as a static library (or a DLL with the proper define set in the ``Preprocessor`` step). + +After that, make sure you grab either the `single header file release`_, or just perform a clone of the `github repository here`_ and set your include paths up so that you can get at ``sol.hpp`` somehow. Note that we also have the latest version of the single header file with all dependencies included kept in the `repository as well`_. We recommend the single-header-file release, since it's easier to move around, manage and update if you commit it with some form of version control. If you use the github clone method and do not point to the `single/sol/sol.hpp`_ on your include files, you *must* update submodules in order to make sure Optional is present in the repository. Clone with: + +>>> git clone https://github.com/ThePhD/sol2.git +>>> git submodule update --init + +or, just run + +>>> git clone --recursive https://github.com/ThePhD/sol2.git + +When you're ready, try compiling this short snippet: + +.. code-block:: cpp + :linenos: + :caption: test.cpp: the first snippet + :name: the-first-snippet + + #include <sol.hpp> // or #include "sol.hpp", whichever suits your needs + + int main (int argc, char* argv[]) { + + sol::state lua; + lua.open_libraries( sol::lib::base ); + + lua.script( "print('bark bark bark!')" ); + + return 0; + } + +Using this simple command line: + +>>> g++ -std=c++14 test.cpp -I"path/to/lua/include" -L"path/to/lua/lib" -llua + +Or using your favorite IDE / tool after setting up your include paths and library paths to Lua according to the documentation of the Lua distribution you got. Remember your linked lua library (``-llua``) and include / library paths will depend on your OS, file system, Lua distribution and your installation / compilation method of your Lua distribution. + +.. note:: + + If you get an avalanche of errors (particularly referring to ``auto``), you may not have enabled C++14 / C++17 mode for your compiler. Add one of ``std=c++14``, ``std=c++1z`` OR ``std=c++1y`` to your compiler options. By default, this is always-on for VC++ compilers in Visual Studio and friends, but g++ and clang++ require a flag (unless you're on `GCC 6.0`_). + +If this works, you're ready to start! The first line creates the ``lua_State`` and will hold onto it for the duration of the scope its declared in (e.g., from the opening ``{`` to the closing ``}``). It will automatically close / cleanup that lua state when it gets destructed. The second line opens a single lua-provided library, "base". There are several other libraries that come with lua that you can open by default, and those are included in the :ref:`sol::lib<lib-enum>` enumeration. You can open multiple base libraries by specifying multiple ``sol::lib`` arguments: + +.. code-block:: cpp + :linenos: + :caption: test.cpp: the first snippet + :name: the-second-snippet + + #include <sol.hpp> + + int main (int argc, char* argv[]) { + + sol::state lua; + lua.open_libraries( sol::lib::base, sol::lib::coroutine, sol::lib::string, sol::lib::io ); + + lua.script( "print('bark bark bark!')" ); + + return 0; + } + +If you're interested in integrating Sol with a project that already uses some other library or Lua in the codebase, check out the :doc:`existing example<existing>` to see how to work with Sol when you add it to a project (the existing example covers ``require`` as well)! + +Next, let's start :doc:`reading/writing some variables<variables>` from Lua into C++, and vice-versa! + + +.. _vanilla Lua: https://www.lua.org/ + +.. _LuaJIT: http://luajit.org/ + +.. _GCC 6.0: https://gcc.gnu.org/gcc-6/changes.html + +.. _single header file release: https://github.com/ThePhD/sol2/releases + +.. _repository as well: https://github.com/ThePhD/sol2/blob/develop/single/sol/sol.hpp + +.. _single/sol/sol.hpp: https://github.com/ThePhD/sol2/blob/develop/single/sol/sol.hpp + +.. _github repository here: https://github.com/ThePhD/sol2 + +.. _Lua page on getting started: https://www.lua.org/start.html
\ No newline at end of file diff --git a/3rdparty/sol2/docs/source/tutorial/ownership.rst b/3rdparty/sol2/docs/source/tutorial/ownership.rst new file mode 100644 index 00000000000..96eb350da78 --- /dev/null +++ b/3rdparty/sol2/docs/source/tutorial/ownership.rst @@ -0,0 +1,94 @@ +ownership +========= + +Sol will not take ownership of raw pointers: raw pointers do not own anything. + +.. code-block:: cpp + + struct my_type { + void stuff () {} + }; + + sol::state lua; + + // AAAHHH BAD + // dangling pointer! + lua["my_func"] = []() -> my_type* { + return new my_type(); + }; + + // AAAHHH! + lua.set("something", new my_type()); + + // AAAAAAHHH!!! + lua["something_else"] = new my_type(); + +Use/return a ``unique_ptr`` or ``shared_ptr`` instead or just return a value: + +.. code-block:: cpp + + // :ok: + lua["my_func"] = []() -> std::unique_ptr<my_type> { + return std::make_unique<my_type>(); + }; + + // :ok: + lua["my_func"] = []() -> std::shared_ptr<my_type> { + return std::make_shared<my_type>(); + }; + + // :ok: + lua["my_func"] = []() -> my_type { + return my_type(); + }; + + // :ok: + lua.set("something", std::unique_ptr<my_type>(new my_type())); + + std::shared_ptr<my_type> my_shared = std::make_shared<my_type>(); + // :ok: + lua.set("something_else", my_shared); + + auto my_unique = std::make_unique<my_type>(); + lua["other_thing"] = std::move(my_unique); + +If you have something you know is going to last and you just want to give it to Lua as a reference, then it's fine too: + +.. code-block:: cpp + + // :ok: + lua["my_func"] = []() -> my_type* { + static my_type mt; + return &mt; + }; + + +Sol can detect ``nullptr``, so if you happen to return it there won't be any dangling because a ``sol::nil`` will be pushed. + +.. code-block:: cpp + + struct my_type { + void stuff () {} + }; + + sol::state lua; + + // BUT THIS IS STILL BAD DON'T DO IT AAAHHH BAD + // return a unique_ptr still or something! + lua["my_func"] = []() -> my_type* { + return nullptr; + }; + + lua["my_func_2"] = [] () -> std::unique_ptr<my_type> { + // default-constructs as a nullptr, + // gets pushed as nil to Lua + return std::unique_ptr<my_type>(); + // same happens for std::shared_ptr + } + + // Acceptable, it will set 'something' to nil + // (and delete it on next GC if there's no more references) + lua.set("something", nullptr); + + // Also fine + lua["something_else"] = nullptr; diff --git a/3rdparty/sol2/docs/source/tutorial/tutorial-top.rst b/3rdparty/sol2/docs/source/tutorial/tutorial-top.rst new file mode 100644 index 00000000000..730423fdb5a --- /dev/null +++ b/3rdparty/sol2/docs/source/tutorial/tutorial-top.rst @@ -0,0 +1,21 @@ +tutorial +======== + +Take some time to learn the framework with thse tutorials. But, if you need to get going FAST, try using the :doc:`quick 'n' dirty<all-the-things>` approach and your browser's / editors search function. It will also serve you well to look at all the `examples`_, which have recently gotten a bit of an overhaul to contain more relevant working examples. + + +.. toctree:: + :caption: Sol Tutorial + :name: tutorialtoc + :maxdepth: 2 + + all-the-things + getting-started + existing + variables + functions + cxx-in-lua + ownership + customization + +.. _examples: https://github.com/ThePhD/sol2/tree/develop/examples diff --git a/3rdparty/sol2/docs/source/tutorial/variables.rst b/3rdparty/sol2/docs/source/tutorial/variables.rst new file mode 100644 index 00000000000..20105bf8003 --- /dev/null +++ b/3rdparty/sol2/docs/source/tutorial/variables.rst @@ -0,0 +1,202 @@ +variables +========= + +Working with variables is easy with Sol, and behaves pretty much like any associative array / map structure you've dealt with previously. Given this lua file that gets loaded into Sol: + +reading +------- + +.. code-block:: lua + :caption: variables.lua + + config = { + fullscreen = false, + resolution = { x = 1024, y = 768 } + } + +.. code-block:: cpp + :caption: main.cpp + :name: variables-main-cpp + + #include <sol.hpp> + + int main () { + + sol::state lua; + lua.script_file( variables.lua ); + + return 0; + } + +You can interact with the variables like this: + +.. code-block:: cpp + :caption: main.cpp extended + :name: extended-variables-main-cpp + + #include <sol.hpp> + #include <tuple> + #include <utility> // for std::pair + + int main () { + + sol::state lua; + lua.script_file( variables.lua ); + + // the type "state" behaves exactly like a table! + bool isfullscreen = lua["config"]["fullscreen"]; // can get nested variables + sol::table config = lua["config"]; + + // can also get it using the "get" member function + // auto replaces the unqualified type name + auto resolution = config.get<sol::table>( "config" ); + + // table and state can have multiple things pulled out of it too + std::pair<int, int> xyresolution = resolution.get<int, int>( "x", "y" ); + // As an example, you can also pull out a tuple as well + std::tuple<int, int> xyresolutiontuple = resolution.get<int, int>( "x", "y" ); + + + return 0; + } + +From this example, you can see that there's many ways to pull out the varaibles you want. You can get For example, to determine if a nested variable exists or not, you can use ``auto`` to capture the value of a ``table[key]`` lookup, and then use the ``.valid()`` method: + +.. code-block:: cpp + :caption: safe lookup + + auto bark = lua["config"]["bark"]; + if (bark.valid()) { + // branch not taken: config / bark is not a variable + } + else { + // Branch taken: config is a not a variable + } + +This comes in handy when you want to check if a nested variable exists. You can also check if a toplevel variable is present or not by using ``sol::optional``, which also checks if A) the keys you're going into exist and B) the type you're trying to get is of a specific type: + +.. code-block:: cpp + :caption: optional lookup + + sol::optional<int> not_an_integer = lua["config"]["fullscreen"]; + if (not_an_integer) { + // Branch not taken: value is not an integer + } + + sol::optoinal<bool> is_a_boolean = lua["config"]["fullscreen"]; + if (is_a_boolean) { + // Branch taken: the value is a boolean + } + + sol::optional<double> does_not_exist = lua["not_a_variable"]; + if (does_not_exist) { + // Branch not taken: that variable is not present + } + +This can come in handy when, even in optimized or release modes, you still want the safety of checking. You can also use the `get_or` methods to, if a certain value may be present but you just want to default the value to something else: + +.. code-block:: cpp + :caption: get_or lookup + + // this will result in a value of '24' + int is_defaulted = lua["config"]["fullscreen"].get_or( 24 ); + + // This will result in the value of the config, which is 'false' + bool is_not_defaulted = lua["config"]["fullscreen"]; + +That's all it takes to read variables! + + +writing +------- + +Writing gets a lot simpler. Even without scripting a file or a string, you can read and write variables into lua as you please: + +.. code-block:: cpp + :caption: main.cpp + :name: writing-main-cpp + + #include <sol.hpp> + #include <iostream> + + int main () { + + sol::state lua; + + // open those basic lua libraries again, like print() etc. + lua.open_libraries( sol::lib::base ); + + // value in the global table + lua["bark"] = 50; + + // a table being created in the global table + lua["some_table"] = lua.create_table_with( + "key0", 24, + "key1", 25, + lua["bark"], "the key is 50 and this string is its value!" + ); + + // Run a plain ol' string of lua code + // Note you can interact with things set through Sol in C++ with lua! + // Using a "Raw String Literal" to have multi-line goodness: http://en.cppreference.com/w/cpp/language/string_literal + lua.script(R"( + + print(some_table[50]) + print(some_table["key0"]) + print(some_table["key1"]) + + -- a lua comment: access a global in a lua script with the _G table + print(_G["bark"]) + + )"); + + return 0; + } + +This example pretty much sums up what can be done. Note that the syntax ``lua["non_existing_key_1"] = 1`` will make that variable, but if you tunnel too deep without first creating a table, the Lua API will panic (e.g., ``lua["does_not_exist"]["b"] = 20`` will trigger a panic). You can also be lazy with reading / writing values: + +.. code-block:: cpp + :caption: main.cpp + :name: lazy-main-cpp + + #include <sol.hpp> + #include <iostream> + + int main () { + + sol::state lua; + + auto barkkey = lua["bark"]; + if (barkkey.valid()) { + // Branch not taken: doesn't exist yet + std::cout << "How did you get in here, arf?!" << std::endl; + } + + barkkey = 50; + if (barkkey.valid()) { + // Branch taken: value exists! + std::cout << "Bark Bjork Wan Wan Wan" << std::endl; + } + } + +Finally, it's possible to erase a reference/variable by setting it to ``nil``, using the constant ``sol::nil`` in C++: + +.. code-block:: cpp + :caption: main.cpp + :name: erase-main-cpp + + #include <sol.hpp> + + int main () { + + sol::state lua; + lua["bark"] = 50; + sol::optional<int> x = lua["bark"]; + // x will have a value + + lua["bark"] = sol::nil; + sol::optional<int> y = lua["bark"]; + // y will not have a value + } + +It's easy to see that there's a lot of options to do what you want here. But, these are just traditional numbers and strings. What if we want more power, more capabilities than what these limited types can offer us? Let's throw some :doc:`functions in there<functions>` :doc:`C++ classes into the mix<cxx-in-lua>`!
\ No newline at end of file |