mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
[ci skip] heavy documentation changes
This commit is contained in:
parent
03d9da41bd
commit
2b45f3a4e8
|
@ -11,10 +11,13 @@ proxy, (protected\_)function_result - proxy_base derivatives
|
||||||
template <typename Table, typename Key>
|
template <typename Table, typename Key>
|
||||||
struct proxy : proxy_base<...>;
|
struct proxy : proxy_base<...>;
|
||||||
|
|
||||||
|
struct stack_proxy: proxy_base<...>;
|
||||||
|
|
||||||
struct function_result : proxy_base<...>;
|
struct function_result : proxy_base<...>;
|
||||||
|
|
||||||
struct protected_function_result: proxy_base<...>;
|
struct protected_function_result: proxy_base<...>;
|
||||||
|
|
||||||
|
|
||||||
These classes provide implicit ``operator=`` (``set``) and ``operator T`` (``get``) support for items retrieved from the underlying Lua implementation in Sol, specifically :doc:`sol::table<table>` and the results of function calls on :doc:`sol::function<function>` and :doc:`sol::protected_function<protected_function>`.
|
These classes provide implicit ``operator=`` (``set``) and ``operator T`` (``get``) support for items retrieved from the underlying Lua implementation in Sol, specifically :doc:`sol::table<table>` and the results of function calls on :doc:`sol::function<function>` and :doc:`sol::protected_function<protected_function>`.
|
||||||
|
|
||||||
|
|
||||||
|
@ -111,7 +114,16 @@ Gets the value associated with the keys the proxy was generated and convers it t
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T get( ) const;
|
T get( ) const;
|
||||||
|
|
||||||
Gets the value associated with the keys the proxy was generated and convers it to the type ``T``.
|
Gets the value associated with the keys and converts it to the type ``T``.
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
:caption: function: optionally get a value
|
||||||
|
:name: regular-get-or
|
||||||
|
|
||||||
|
template <typename T, typename Otherwise>
|
||||||
|
optional<T> get_or( Otherwise&& otherise ) const;
|
||||||
|
|
||||||
|
Gets the value associated with the keys and converts it to the type ``T``. If it is not of the proper type, it will return a ``sol::nullopt`` instead.
|
||||||
|
|
||||||
``operator[]`` proxy-only members
|
``operator[]`` proxy-only members
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
@ -157,6 +169,10 @@ Sets the value associated with the keys the proxy was generated with to a functi
|
||||||
|
|
||||||
Sets the value associated with the keys the proxy was generated with to ``value``. Does not exist on :ref:`function_result<function-result>` or :ref:`protected_function_result<protected-function-result>`.
|
Sets the value associated with the keys the proxy was generated with to ``value``. Does not exist on :ref:`function_result<function-result>` or :ref:`protected_function_result<protected-function-result>`.
|
||||||
|
|
||||||
|
stack_proxy
|
||||||
|
-----------
|
||||||
|
|
||||||
|
``sol::stack_proxy`` is what gets returned by :doc:`sol::variadic_args<variadic_args>` and other parts of the framework. It is similar to proxy, but is meant to alias a stack index and not a named function.
|
||||||
|
|
||||||
.. _note 1:
|
.. _note 1:
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ transparent argument to deal with multiple parameters to a function
|
||||||
|
|
||||||
This class is meant to represent every single argument at its current index and beyond in a function list. It does not increment the argument count and is thus transparent. You can place it anyway in the argument list, and it will represent all of the objects in a function call that come after it, whether they are listed explicitly or not.
|
This class is meant to represent every single argument at its current index and beyond in a function list. It does not increment the argument count and is thus transparent. You can place it anyway in the argument list, and it will represent all of the objects in a function call that come after it, whether they are listed explicitly or not.
|
||||||
|
|
||||||
|
``variadic_args`` also has ``begin()`` and ``end()`` functions that return (almost) random-acess iterators. These return a proxy type that can be implicitly converted, much like the :doc:`table proxy type<proxy>`.
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
:linenos:
|
:linenos:
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ todo_include_todos = True
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
html_theme = 'alabaster'
|
html_theme = "haiku"
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
|
@ -123,7 +123,7 @@ html_theme = 'alabaster'
|
||||||
#html_theme_options = {}
|
#html_theme_options = {}
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
#html_theme_path = []
|
html_theme_path = ["_themes", ]
|
||||||
|
|
||||||
# The name for this set of Sphinx documents. If None, it defaults to
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
# "<project> v<release> documentation".
|
# "<project> v<release> documentation".
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
You can adapt this file completely to your liking, but it should at least
|
You can adapt this file completely to your liking, but it should at least
|
||||||
contain the root `toctree` directive.
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
|
.. image:: sol.png
|
||||||
|
:target: https://github.com/ThePhD/sol2
|
||||||
|
:alt: sol2 repository
|
||||||
|
|
||||||
Sol 2.5
|
Sol 2.5
|
||||||
=======
|
=======
|
||||||
a fast, simple C++ and Lua Binding
|
a fast, simple C++ and Lua Binding
|
||||||
|
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
docs/source/sol.psd
Normal file
BIN
docs/source/sol.psd
Normal file
Binary file not shown.
|
@ -64,23 +64,47 @@ You can set/get everything.
|
||||||
|
|
||||||
// integer types
|
// integer types
|
||||||
lua.set("number", 24);
|
lua.set("number", 24);
|
||||||
|
|
||||||
// floating point numbers
|
// floating point numbers
|
||||||
lua["number2"] = 24.5;
|
lua["number2"] = 24.5;
|
||||||
|
|
||||||
// string types
|
// string types
|
||||||
lua["important_string"] = "woof woof";
|
lua["important_string"] = "woof woof";
|
||||||
|
|
||||||
// non-recognized types is stored as userdata
|
// non-recognized types is stored as userdata
|
||||||
// this moves the type in (or copies, depending on class semantics)
|
|
||||||
lua["myuserdata"] = some_class();
|
|
||||||
// is callable, therefore gets stored as a function
|
// is callable, therefore gets stored as a function
|
||||||
lua["a_function"] = [](){ return 100; };
|
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
|
// implicit conversion
|
||||||
int number = lua["number"];
|
int number = lua["number"];
|
||||||
|
|
||||||
// explicit get
|
// explicit get
|
||||||
auto number2 = lua.get<double>("number2");
|
auto number2 = lua.get<double>("number2");
|
||||||
|
|
||||||
// strings too
|
// strings too
|
||||||
std::string important_string = lua["important_string"];
|
std::string important_string = lua["important_string"];
|
||||||
|
|
||||||
|
// dig into a table
|
||||||
|
int value = lua["value"]["value"];
|
||||||
|
|
||||||
// get a function
|
// get a function
|
||||||
sol::function a_function = lua["a_function"];
|
sol::function a_function = lua["a_function"];
|
||||||
int value_is_100 = a_function();
|
int value_is_100 = a_function();
|
||||||
|
@ -240,7 +264,7 @@ They're great. Use them:
|
||||||
|
|
||||||
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>`.
|
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:
|
You can bind member variables as functions too, as well as all KINDS of function-like things:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
@ -248,6 +272,10 @@ You can bind member variables as functions too:
|
||||||
std::cout << "some function!" << std::endl;
|
std::cout << "some function!" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void some_other_function () {
|
||||||
|
std::cout << "some other function!" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
struct some_class {
|
struct some_class {
|
||||||
int variable = 30;
|
int variable = 30;
|
||||||
|
|
||||||
|
@ -259,48 +287,56 @@ You can bind member variables as functions too:
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
lua.open_libraries(sol::lib::base);
|
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["f1"] = some_function;
|
||||||
lua.set_function("f2", &some_other_function);
|
lua.set_function("f2", &some_other_function);
|
||||||
|
|
||||||
lua.script(R"(
|
|
||||||
f1() -- some function!
|
|
||||||
f2() -- some function!
|
|
||||||
)");
|
|
||||||
|
|
||||||
// put an instance of "some_class" into lua
|
|
||||||
lua.set("sc", some_class());
|
|
||||||
|
|
||||||
// binds just the member function
|
// binds just the member function
|
||||||
lua["m1"] = &some_class::member_function;
|
lua["m1"] = &some_class::member_function;
|
||||||
|
|
||||||
// binds the class to the type
|
// binds the class to the type
|
||||||
lua.set_function("m2", &some_class::member_function, some_class{});
|
lua.set_function("m2", &some_class::member_function, some_class{});
|
||||||
|
|
||||||
lua.script(R"(
|
|
||||||
-- need class instance if you don't bind it with the function
|
|
||||||
print(m1(sc)) -- 24.5
|
|
||||||
-- does not need class instance: was made with one
|
|
||||||
print(m2()) -- 24.5
|
|
||||||
)");
|
|
||||||
|
|
||||||
// binds just the member variable as a function
|
// binds just the member variable as a function
|
||||||
lua["v1"] = &some_class::variable;
|
lua["v1"] = &some_class::variable;
|
||||||
|
|
||||||
// binds class with member variable as function
|
// binds class with member variable as function
|
||||||
lua.set_function("v2", &some_class::variable, some_class{});
|
lua.set_function("v2", &some_class::variable, some_class{});
|
||||||
|
|
||||||
lua.script(R"(
|
The lua code to call these things is:
|
||||||
-- need class instance if you don't bind it with the function
|
|
||||||
print(v1(sc)) -- 30
|
|
||||||
-- does not need class instance: was bound with one
|
|
||||||
print(v2()) -- 30
|
|
||||||
|
|
||||||
-- can set: still requires instance
|
.. code-block:: lua
|
||||||
v1(sc, 212)
|
|
||||||
-- can set: does not need class instance: was bound with one
|
|
||||||
v2(254)
|
|
||||||
|
|
||||||
print(v1(sc)) -- 212
|
f1() -- some function!
|
||||||
print(v2()) -- 254
|
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 made 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.
|
Can use ``sol::readonly( &some_class::variable )`` to make a variable readonly and error if someone tries to write to it.
|
||||||
|
|
||||||
|
@ -314,8 +350,8 @@ multiple returns from lua
|
||||||
|
|
||||||
lua.script("function f (a, b, c) return a, b, c end");
|
lua.script("function f (a, b, c) return a, b, c end");
|
||||||
|
|
||||||
std::tuple<int, int, int> result
|
std::tuple<int, int, int> result;
|
||||||
= lua["f"](100, 200, 300);
|
result = lua["f"](100, 200, 300);
|
||||||
// result == { 100, 200, 300 }
|
// result == { 100, 200, 300 }
|
||||||
int a, int b;
|
int a, int b;
|
||||||
std::string c;
|
std::string c;
|
||||||
|
@ -340,9 +376,10 @@ multiple returns to lua
|
||||||
std::tuple<int, int, int> result = lua["f"](100, 200, 300);
|
std::tuple<int, int, int> result = lua["f"](100, 200, 300);
|
||||||
// result == { 100, 200, 300 }
|
// result == { 100, 200, 300 }
|
||||||
|
|
||||||
std::tuple<int, int, std::string> resutl2
|
std::tuple<int, int, std::string> result2;
|
||||||
= lua["f"](100, 200, "BARK BARK BARK!")
|
result2 = lua["f"](100, 200, "BARK BARK BARK!")
|
||||||
// result == { 100, 200, "BARK BARK BARK!" }
|
// result2 == { 100, 200, "BARK BARK BARK!" }
|
||||||
|
|
||||||
int a, int b;
|
int a, int b;
|
||||||
std::string c;
|
std::string c;
|
||||||
sol::tie( a, b, c ) = lua["f"](100, 200, "bark");
|
sol::tie( a, b, c ) = lua["f"](100, 200, "bark");
|
||||||
|
@ -351,8 +388,8 @@ multiple returns to lua
|
||||||
// c == "bark"
|
// c == "bark"
|
||||||
|
|
||||||
|
|
||||||
C++ classes in from C++
|
C++ classes from C++
|
||||||
-----------------------
|
--------------------
|
||||||
|
|
||||||
Everything that is not a:
|
Everything that is not a:
|
||||||
|
|
||||||
|
@ -454,220 +491,17 @@ Note that you can change the data of usertype variables and it will affect thing
|
||||||
lua.script("assert(dog.tailwag == 100)");
|
lua.script("assert(dog.tailwag == 100)");
|
||||||
|
|
||||||
|
|
||||||
C++ classes in Lua
|
C++ classes put into Lua
|
||||||
------------------
|
------------------------
|
||||||
|
|
||||||
Because there's a LOT you can do with Sol:
|
See this :doc:`section here<cxx-in-lua>`.
|
||||||
|
|
||||||
.. 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int set_hp(int value) {
|
|
||||||
hp = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_hp() const {
|
|
||||||
return hp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int hp;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bind all the things:
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
|
||||||
:caption: player_script.cpp
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
And the script:
|
|
||||||
|
|
||||||
.. 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.set(...) above
|
|
||||||
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()
|
|
||||||
|
|
||||||
Even more stuff :doc:`you can do<../api/usertype>` described elsewhere, like initializer functions (private constructors / destructors support), "static" functions callable with ``name.my_function( ... )``, and overloaded member functions.
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
|
|
||||||
advanced
|
advanced
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Some more advanced things you can do:
|
Some more advanced things you can do/read about:
|
||||||
|
* :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:`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:`stack references<../api/stack_reference>` to have zero-overhead Sol abstractions while not copying to the Lua registry.
|
* :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:`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.
|
||||||
|
|
|
@ -1,4 +1,124 @@
|
||||||
C++ in Lua
|
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. [ WIP - Check back soon. Until its done, use the :doc:`quick 'n' dirty<all-the-things>` and the :doc:`api<../api/api-top>` to get going! ]
|
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. 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int 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, so that we can make the following script work:
|
||||||
|
|
||||||
|
.. 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.set(...) above
|
||||||
|
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 Sol like so:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
:caption: player_script.cpp
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// 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.
|
87
docs/source/tutorial/ownership.rst
Normal file
87
docs/source/tutorial/ownership.rst
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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;
|
|
@ -15,3 +15,4 @@ Take some time to learn the framework with thse tutorials. But, if you need to g
|
||||||
variables
|
variables
|
||||||
functions
|
functions
|
||||||
cxx-in-lua
|
cxx-in-lua
|
||||||
|
ownership
|
||||||
|
|
Loading…
Reference in New Issue
Block a user