mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
heavily improve examples and docs
This commit is contained in:
parent
60332562fd
commit
fd6feec382
|
@ -1,4 +1,4 @@
|
||||||
## sol3 (sol2 v3.0.2)
|
## sol3 (sol2 v3.0.3)
|
||||||
|
|
||||||
[![Join the chat in Discord: https://discord.gg/buxkYNT](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/buxkYNT)
|
[![Join the chat in Discord: https://discord.gg/buxkYNT](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/buxkYNT)
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ author = 'ThePhD'
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '3.0'
|
version = '3.0'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '3.0.2'
|
release = '3.0.3'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|
|
@ -5,131 +5,34 @@ Using user defined types ("usertype"s, or just "udt"s) is simple with sol. If yo
|
||||||
|
|
||||||
Take this ``player`` struct in C++ in a header file:
|
Take this ``player`` struct in C++ in a header file:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. literalinclude:: ../../../examples/source/usertype_advanced.cpp
|
||||||
:caption: test_player.hpp
|
:caption: player.hpp
|
||||||
|
:linenos:
|
||||||
struct player {
|
:lines: 1-48
|
||||||
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:
|
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
|
.. literalinclude:: ../../../examples/source/usertype_advanced.cpp
|
||||||
:caption: player_script.lua
|
:caption: player_script.lua
|
||||||
|
:language: lua
|
||||||
|
:linenos:
|
||||||
|
:lines: 93-124
|
||||||
|
|
||||||
-- call single argument integer constructor
|
To do this, you bind things using the ``new_usertype`` and method 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``:
|
||||||
p1 = player.new(2)
|
|
||||||
|
|
||||||
-- p2 is still here from being
|
.. literalinclude:: ../../../examples/source/usertype_advanced.cpp
|
||||||
-- set with lua["p2"] = player(0);
|
:caption: main.cpp
|
||||||
-- in cpp file
|
:language: cpp
|
||||||
local p2shoots = p2:shoot()
|
:linenos:
|
||||||
assert(not p2shoots)
|
:lines: 1-3,5,7-9,53,55-86,136-137,142
|
||||||
-- had 0 ammo
|
|
||||||
|
|
||||||
-- set variable property setter
|
There is one more method used in the script that is not in C++ or defined on the C++ code to bind a usertype, called ``brake``. Even if a method does not exist in C++, you can add methods to the *class table* in Lua:
|
||||||
p1.hp = 545;
|
|
||||||
-- get variable through property getter
|
|
||||||
print(p1.hp);
|
|
||||||
|
|
||||||
local did_shoot_1 = p1:shoot()
|
.. literalinclude:: ../../../examples/source/usertype_advanced.cpp
|
||||||
print(did_shoot_1)
|
:caption: prelude_script.lua
|
||||||
print(p1.bullets)
|
:language: lua
|
||||||
local did_shoot_2 = p1:shoot()
|
:linenos:
|
||||||
print(did_shoot_2)
|
:lines: 90-93
|
||||||
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/sol.hpp>
|
|
||||||
|
|
||||||
int main () {
|
|
||||||
sol::state lua;
|
|
||||||
|
|
||||||
lua.open_libraries(sol::lib::base);
|
|
||||||
|
|
||||||
// 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<player(), player(int), player(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!
|
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!
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ 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.
|
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).
|
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`` page, eg. `LUA_BUILD_AS_DLL=1`).
|
||||||
|
|
||||||
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. You can also clone/submodule the repository and then point at the `single/sol/sol.hpp`_ on your include files path. Clone with:
|
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. You can also clone/submodule the repository and then point at the `single/sol/sol.hpp`_ on your include files path. Clone with:
|
||||||
|
|
||||||
|
@ -11,53 +11,27 @@ After that, make sure you grab either the `single header file release`_, or just
|
||||||
|
|
||||||
When you're ready, try compiling this short snippet:
|
When you're ready, try compiling this short snippet:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. literalinclude:: ../../../examples/source/tutorials/first_snippet.cpp
|
||||||
:linenos:
|
:linenos:
|
||||||
:caption: test.cpp: the first snippet
|
:caption: hello_lua.cpp
|
||||||
:name: the-first-snippet
|
|
||||||
|
|
||||||
#include <sol/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:
|
Using this simple command line:
|
||||||
|
|
||||||
>>> g++ -std=c++14 test.cpp -I"path/to/lua/include" -L"path/to/lua/lib" -llua
|
>>> g++ -std=c++17 test.cpp -I"path/to/sol/include" -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.
|
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::
|
.. 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`_ or better).
|
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++17``, ``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`_ or better).
|
||||||
|
|
||||||
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.
|
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:
|
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
|
.. literalinclude:: ../../../examples/source/tutorials/open_multiple_libraries.cpp
|
||||||
:linenos:
|
:linenos:
|
||||||
:caption: test.cpp: the first snippet
|
:caption: multiple_libraries.cpp
|
||||||
:name: the-second-snippet
|
|
||||||
|
|
||||||
#include <sol/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)!
|
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)!
|
||||||
|
|
||||||
|
|
|
@ -1,127 +1,58 @@
|
||||||
ownership
|
ownership
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
Ownership is important when managing resources in C++. sol has many ownership semantics which are generally safe by default. Below are the rules.
|
||||||
|
|
||||||
|
object ownership
|
||||||
|
----------------
|
||||||
|
|
||||||
You can take a reference to something that exists in Lua by pulling out a :doc:`sol::reference<../api/reference>` or a :doc:`sol::object<../api/object>`:
|
You can take a reference to something that exists in Lua by pulling out a :doc:`sol::reference<../api/reference>` or a :doc:`sol::object<../api/object>`:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. literalinclude:: ../../../examples/source/tutorials/object_lifetime.cpp
|
||||||
|
:linenos:
|
||||||
|
:caption: object_lifetime.cpp
|
||||||
|
|
||||||
sol::state lua;
|
All objects must be destroyed before the `sol::state` is destroyed, otherwise you will end up with dangling references to the Lua State and things will explode in horrible, terrible fashion.
|
||||||
lua.open_libraries(sol::lib::base);
|
|
||||||
|
|
||||||
lua.script(R"(
|
This applies to more than just `sol::object`: all types derived from `sol::reference` and `sol::object` (:doc:`sol::table<../api/table>` :doc:`sol::userdata<../api/userdata>`, etc.) must be cleaned up before the state goes out of scope.
|
||||||
obj = "please don't let me die";
|
|
||||||
)");
|
|
||||||
|
|
||||||
sol::object keep_alive = lua["obj"];
|
|
||||||
lua.script(R"(
|
|
||||||
obj = nil;
|
|
||||||
function say(msg)
|
|
||||||
print(msg)
|
|
||||||
end
|
|
||||||
)");
|
|
||||||
|
|
||||||
lua.collect_garbage();
|
|
||||||
|
|
||||||
lua["say"](lua["obj"]);
|
|
||||||
// still accessible here and still alive in Lua
|
|
||||||
// even though the name was cleared
|
|
||||||
std::string message = keep_alive.as<std::string>();
|
|
||||||
std::cout << message << std::endl;
|
|
||||||
|
|
||||||
// Can be pushed back into Lua as an argument
|
|
||||||
// or set to a new name,
|
|
||||||
// whatever you like!
|
|
||||||
lua["say"](keep_alive);
|
|
||||||
|
|
||||||
|
pointer ownership
|
||||||
|
-----------------
|
||||||
|
|
||||||
sol will not take ownership of raw pointers: raw pointers do not own anything. sol will not delete raw pointers, because they do not (and are not supposed to) own anything:
|
sol will not take ownership of raw pointers: raw pointers do not own anything. sol will not delete raw pointers, because they do not (and are not supposed to) own anything:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. literalinclude:: ../../../examples/source/tutorials/pointer_lifetime.cpp
|
||||||
|
:linenos:
|
||||||
struct my_type {
|
:caption: pointer_lifetime.cpp
|
||||||
void stuff () {}
|
:lines: 1-11,14-22, 74-
|
||||||
};
|
|
||||||
|
|
||||||
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:
|
Use/return a ``unique_ptr`` or ``shared_ptr`` instead or just return a value:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. literalinclude:: ../../../examples/source/tutorials/pointer_lifetime.cpp
|
||||||
|
:linenos:
|
||||||
// :ok:
|
:caption: (smart pointers) pointer_lifetime.cpp
|
||||||
lua["my_func"] = []() -> std::unique_ptr<my_type> {
|
:lines: 1-11,14-22, 74-
|
||||||
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:
|
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
|
.. literalinclude:: ../../../examples/source/tutorials/pointer_lifetime.cpp
|
||||||
|
:linenos:
|
||||||
// :ok:
|
:caption: (static) pointer_lifetime.cpp
|
||||||
lua["my_func"] = []() -> my_type* {
|
:lines: 1-11,46-49,74-
|
||||||
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.
|
sol can detect ``nullptr``, so if you happen to return it there won't be any dangling because a ``sol::lua_nil`` will be pushed. But if you know it's ``nil`` beforehand, please return ``std::nullptr_t`` or ``sol::lua_nil``:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. literalinclude:: ../../../examples/source/tutorials/pointer_lifetime.cpp
|
||||||
|
:linenos:
|
||||||
|
:caption: (nil/nullptr) pointer_lifetime.cpp
|
||||||
|
:lines: 1-11,51-
|
||||||
|
|
||||||
struct my_type {
|
|
||||||
void stuff () {}
|
|
||||||
};
|
|
||||||
|
|
||||||
sol::state lua;
|
ephermeal (proxy) objects
|
||||||
|
-------------------------
|
||||||
|
|
||||||
// BUT THIS IS STILL BAD DON'T DO IT AAAHHH BAD
|
:doc:`Proxy<../api/proxy>` and result types are ephermeal. They rely on the Lua stack and their constructors / destructors interact with the Lua stack. This means they are entirely unsafe to return from functions in C++, without very careful attention paid to how they are used that often requires relying on implementation-defined behaviors.
|
||||||
// return a unique_ptr still or something!
|
|
||||||
lua["my_func"] = []() -> my_type* {
|
|
||||||
return nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
lua["my_func_2"] = [] () -> std::unique_ptr<my_type> {
|
Please be careful when using `(protected_)function_result`, `load_result` (especially multiple load/function results in a single C++ function!) `stack_reference`, and similar stack-based things. If you want to return these things, consider
|
||||||
// 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;
|
|
||||||
|
|
|
@ -27,11 +27,6 @@ The examples folder also has a number of really great examples for you to see. T
|
||||||
* (Advanced) Interop with ``toLua``, ``kaguya``, ``OOLua``, ``LuaBind``, ``luwra``, and all other existing libraries by using the stack API's ``sol::stack::userdata_checker`` and ``sol::stack::userdata_getter`` :ref:`extension points<extension_points>`
|
* (Advanced) Interop with ``toLua``, ``kaguya``, ``OOLua``, ``LuaBind``, ``luwra``, and all other existing libraries by using the stack API's ``sol::stack::userdata_checker`` and ``sol::stack::userdata_getter`` :ref:`extension points<extension_points>`
|
||||||
- Must turn on ``SOL_ENABLE_INTEROP``, as defined in the :ref:`configuration and safety documentation<config>`, to use
|
- Must turn on ``SOL_ENABLE_INTEROP``, as defined in the :ref:`configuration and safety documentation<config>`, to use
|
||||||
|
|
||||||
.. _usertype-special-features:
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Note that to use many of sol3's features, such as automatic constructor creation, ``sol::property``, and similar, one must pass these things to the usertype as part of its initial creation and grouping of arguments. Attempting to do so afterwards will result in unexpected and wrong behavior, as the system will be missing information it needs. This is because many of these features rely on ``__index`` and ``__newindex`` Lua metamethods being overridden and handled in a special way!
|
|
||||||
|
|
||||||
Here are some other general advice and tips for understanding and dealing with usertypes:
|
Here are some other general advice and tips for understanding and dealing with usertypes:
|
||||||
|
|
||||||
* Please note that the colon is necessary to "automatically" pass the ``this``/``self`` argument to Lua methods
|
* Please note that the colon is necessary to "automatically" pass the ``this``/``self`` argument to Lua methods
|
||||||
|
|
|
@ -49,7 +49,7 @@ endif()
|
||||||
|
|
||||||
# # single-source compilable examples
|
# # single-source compilable examples
|
||||||
|
|
||||||
file(GLOB EXAMPLES_SRC source/*.cpp source/tutorials/quick_n_dirty/*.cpp source/docs/*.cpp)
|
file(GLOB EXAMPLES_SRC source/*.cpp source/tutorials/*.cpp source/tutorials/quick_n_dirty/*.cpp source/docs/*.cpp)
|
||||||
source_group(examples FILES ${EXAMPLES_SRC})
|
source_group(examples FILES ${EXAMPLES_SRC})
|
||||||
|
|
||||||
function (MAKE_EXAMPLE example_source_file example_suffix target_sol)
|
function (MAKE_EXAMPLE example_source_file example_suffix target_sol)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#define SOL_ALL_SAFETIES_ON 1
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
#include <sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
|
|
12
examples/source/tutorials/first_snippet.cpp
Normal file
12
examples/source/tutorials/first_snippet.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
|
#include <sol/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;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
#define SOL_ALL_SAFETIES_ON 1
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
#include <sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
37
examples/source/tutorials/object_lifetime.cpp
Normal file
37
examples/source/tutorials/object_lifetime.cpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
sol::state lua;
|
||||||
|
lua.open_libraries(sol::lib::base);
|
||||||
|
|
||||||
|
lua.script(R"(
|
||||||
|
obj = "please don't let me die";
|
||||||
|
)");
|
||||||
|
|
||||||
|
sol::object keep_alive = lua["obj"];
|
||||||
|
lua.script(R"(
|
||||||
|
obj = nil;
|
||||||
|
function say(msg)
|
||||||
|
print(msg)
|
||||||
|
end
|
||||||
|
)");
|
||||||
|
|
||||||
|
lua.collect_garbage();
|
||||||
|
|
||||||
|
lua["say"](lua["obj"]);
|
||||||
|
// still accessible here and still alive in Lua
|
||||||
|
// even though the name was cleared
|
||||||
|
std::string message = keep_alive.as<std::string>();
|
||||||
|
std::cout << message << std::endl;
|
||||||
|
|
||||||
|
// Can be pushed back into Lua as an argument
|
||||||
|
// or set to a new name,
|
||||||
|
// whatever you like!
|
||||||
|
lua["say"](keep_alive);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
12
examples/source/tutorials/open_multiple_libraries.cpp
Normal file
12
examples/source/tutorials/open_multiple_libraries.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
|
#include <sol/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;
|
||||||
|
}
|
75
examples/source/tutorials/pointer_lifetime.cpp
Normal file
75
examples/source/tutorials/pointer_lifetime.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
|
struct my_type {
|
||||||
|
void stuff() {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
|
||||||
|
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();
|
||||||
|
*/
|
||||||
|
|
||||||
|
// :ok:
|
||||||
|
lua["my_func0"] = []() -> std::unique_ptr<my_type> { return std::make_unique<my_type>(); };
|
||||||
|
|
||||||
|
// :ok:
|
||||||
|
lua["my_func1"] = []() -> std::shared_ptr<my_type> { return std::make_shared<my_type>(); };
|
||||||
|
|
||||||
|
// :ok:
|
||||||
|
lua["my_func2"] = []() -> 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);
|
||||||
|
|
||||||
|
// :ok:
|
||||||
|
auto my_unique = std::make_unique<my_type>();
|
||||||
|
lua["other_thing"] = std::move(my_unique);
|
||||||
|
|
||||||
|
// :ok:
|
||||||
|
lua["my_func5"] = []() -> my_type* {
|
||||||
|
static my_type mt;
|
||||||
|
return &mt;
|
||||||
|
};
|
||||||
|
|
||||||
|
// THIS IS STILL BAD DON'T DO IT AAAHHH BAD
|
||||||
|
// return a unique_ptr that's empty instead
|
||||||
|
// or be explicit!
|
||||||
|
lua["my_func6"] = []() -> my_type* { return nullptr; };
|
||||||
|
|
||||||
|
// :ok:
|
||||||
|
lua["my_func7"] = []() -> std::nullptr_t { return nullptr; };
|
||||||
|
|
||||||
|
// :ok:
|
||||||
|
lua["my_func8"] = []() -> 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;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
#define SOL_ALL_SAFETIES_ON 1
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
#include <sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <assert.hpp>
|
#include <assert.hpp>
|
||||||
|
@ -21,7 +21,7 @@ config = {
|
||||||
// exactly like a table!
|
// exactly like a table!
|
||||||
bool isfullscreen = lua["config"]["fullscreen"]; // can get nested variables
|
bool isfullscreen = lua["config"]["fullscreen"]; // can get nested variables
|
||||||
sol::table config = lua["config"];
|
sol::table config = lua["config"];
|
||||||
c_assert(isfullscreen);
|
c_assert(!isfullscreen);
|
||||||
|
|
||||||
// can also get it using the "get" member function
|
// can also get it using the "get" member function
|
||||||
// auto replaces the unqualified type name
|
// auto replaces the unqualified type name
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#define SOL_ALL_SAFETIES_ON 1
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
#include <sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#define SOL_ALL_SAFETIES_ON 1
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
#include <sol/sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "player.hpp"
|
||||||
|
*/
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
struct player {
|
struct player {
|
||||||
|
@ -78,7 +82,7 @@ int main() {
|
||||||
"speed", &player::speed,
|
"speed", &player::speed,
|
||||||
// can only read from, not write to
|
// can only read from, not write to
|
||||||
"bullets", sol::readonly(&player::bullets)
|
"bullets", sol::readonly(&player::bullets)
|
||||||
);
|
);
|
||||||
|
|
||||||
// You can also add members to the code, defined in Lua!
|
// You can also add members to the code, defined in Lua!
|
||||||
// This lets you have a high degree of flexibility in the code
|
// This lets you have a high degree of flexibility in the code
|
||||||
|
@ -127,8 +131,11 @@ p1:brake()
|
||||||
// Uncomment and use the file to try that out, too!
|
// Uncomment and use the file to try that out, too!
|
||||||
// Make sure it's in the local directory of the executable after you build, or adjust the filename path
|
// Make sure it's in the local directory of the executable after you build, or adjust the filename path
|
||||||
// Or whatever else you like!
|
// Or whatever else you like!
|
||||||
//lua.script_file("prelude_script.lua");
|
//
|
||||||
//lua.script_file("player_script.lua");
|
/*
|
||||||
|
lua.script_file("prelude_script.lua");
|
||||||
|
lua.script_file("player_script.lua");
|
||||||
|
*/
|
||||||
lua.script(prelude_script);
|
lua.script(prelude_script);
|
||||||
lua.script(player_script);
|
lua.script(player_script);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user