mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
prepare for new usertype
change how type T is gleaned from destructors and constructors in case of new syntax add a hell of a lot more examples, update and clean documentation
This commit is contained in:
parent
3f65ad43d8
commit
6c40c559e3
@ -112,12 +112,12 @@ include(CMakePackageConfigHelpers)
|
||||
set(LUA_VERSION "5.3.4" CACHE STRING "The version of Lua needed. Can be 5.1, 5.2, 5.3, LuaJIT, or a more specific 3-part version number for a specifc Lua (e.g., 5.3.4 or luajit-2.0.5)")
|
||||
set(BUILD_LUA TRUE CACHE BOOL "Always build Lua, do not search for it in the system")
|
||||
set(PLATFORM "x64" CACHE STRING "Target platform to compile for when building binaries (x86, x64)")
|
||||
option(CI "Enable build of tests" OFF)
|
||||
option(CI "Whether or not we are in continguous integration mode" OFF)
|
||||
option(TESTS "Enable build of tests" OFF)
|
||||
option(EXAMPLES "Enable build of examples" OFF)
|
||||
option(INTEROP_EXAMPLES "Enable build of interop examples" OFF)
|
||||
option(DYNAMIC_LOADING_EXAMPLES "Enable build of interop examples" OFF)
|
||||
option(SINGLE "Enable build of single header files" ON)
|
||||
option(SINGLE "Enable build of single header files" OFF)
|
||||
option(DOCS "Enable build of documentation" OFF)
|
||||
# Single tests and examples tests will only be turned on if both SINGLE and TESTS are defined
|
||||
CMAKE_DEPENDENT_OPTION(TESTS_SINGLE "Enable build of tests using the generated single headers" ON
|
||||
|
@ -212,7 +212,7 @@ else ()
|
||||
set(LUA_JIT_PREBUILT_EXP ${LUA_JIT_LIB_EXP_FILENAME})
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND LUA_JIT_MAKE_BUILD_MODIFICATIONS "HOST_SYS=Windows" "TARGET_SYS=Windows")
|
||||
list(APPEND LUA_JIT_MAKE_BUILD_MODIFICATIONS "HOST_SYS=Windows" "TARGET_SYS=Windows" "TARGET_AR=ar rcus")
|
||||
endif()
|
||||
list(APPEND LUA_JIT_MAKE_BUILD_MODIFICATIONS "CFLAGS=${LUA_JIT_MAKE_CFLAGS_MODIFICATIONS}")
|
||||
list(APPEND LUA_JIT_MAKE_BUILD_MODIFICATIONS "TARGET_CFLAGS=${LUA_JIT_MAKE_TARGET_CFLAGS_MODIFICATIONS}")
|
||||
|
@ -19,7 +19,6 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo
|
||||
environment
|
||||
this_environment
|
||||
proxy
|
||||
containers
|
||||
as_container
|
||||
nested
|
||||
as_table
|
||||
|
@ -14,37 +14,10 @@ as_args
|
||||
|
||||
``sol::as_args`` is a function that that takes an iterable and turns it into multiple arguments to a function call. It forwards its arguments, and is meant to be used as shown below:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
.. literalinclude:: ../../../examples/args_from_container.cpp
|
||||
:caption: args_from_container.cpp
|
||||
:linenos:
|
||||
:caption: as_args.c++
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
lua.script("function f (a, b, c, d) print(a, b, c, d) end");
|
||||
|
||||
sol::function f = lua["f"];
|
||||
|
||||
std::vector<int> v2{ 3, 4 };
|
||||
f(1, 2, sol::as_args(v2));
|
||||
|
||||
std::set<int> v4{ 3, 1, 2, 4 };
|
||||
f(sol::as_args(v4));
|
||||
|
||||
int v3[] = { 2, 3, 4 };
|
||||
f(1, sol::as_args(v3));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
It is basically implemented as a `one-way customization point`_. For more information about customization points, see the :doc:`tutorial on how to customize Sol to work with your types<../tutorial/customization>`.
|
||||
|
||||
|
@ -12,56 +12,13 @@ This function serves the purpose of ensuring that a callable struct (like a lamb
|
||||
|
||||
This class can also make it so usertypes bind variable types as functions to for usertype bindings.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <sol.hpp>
|
||||
|
||||
int main () {
|
||||
struct callable {
|
||||
int operator()( int a, bool b ) {
|
||||
return a + b ? 10 : 20;
|
||||
}
|
||||
};
|
||||
.. literalinclude:: ../../../examples/docs/as_function.cpp
|
||||
:linenos:
|
||||
|
||||
|
||||
sol::state lua;
|
||||
// Binds struct as userdata
|
||||
lua.set( "not_func", callable() );
|
||||
// Binds struct as function
|
||||
lua.set( "func", sol::as_function( callable() ) );
|
||||
// equivalent: lua.set_function( "func", callable() );
|
||||
// equivalent: lua["func"] = callable();
|
||||
}
|
||||
|
||||
Note that if you actually want a userdata, but you want it to be callable, you simply need to create a :ref:`sol::table::new_usertype<new-usertype>` and then bind the ``"__call"`` metamethod (or just use ``sol::meta_function::call`` :ref:`enumeration<meta_function_enum>`).
|
||||
Note that if you actually want a userdata, but you want it to be callable, you simply need to create a :ref:`sol::table::new_usertype<new-usertype>` and then bind the ``"__call"`` metamethod (or just use ``sol::meta_function::call`` :ref:`enumeration<meta_function_enum>`). This may or may not be done automatically for you, depending on whether or not the call operator is overloaded and such.
|
||||
|
||||
Here's an example of binding a variable as a function to a usertype:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <sol.hpp>
|
||||
|
||||
int main () {
|
||||
class B {
|
||||
public:
|
||||
int bvar = 24;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
lua.new_usertype<B>("B",
|
||||
// bind as variable
|
||||
"b", &B::bvar,
|
||||
// bind as function
|
||||
"f", sol::as_function(&B::bvar)
|
||||
);
|
||||
|
||||
B b;
|
||||
lua.set("b", &b);
|
||||
lua.script("x = b:f()");
|
||||
lua.script("y = b.b");
|
||||
int x = lua["x"];
|
||||
int y = lua["y"];
|
||||
assert(x == 24);
|
||||
assert(y == 24);
|
||||
}
|
||||
.. literalinclude:: ../../../examples/docs/as_function_usertype_member_variable.cpp
|
||||
:linenos:
|
||||
|
@ -15,36 +15,5 @@ as_returns
|
||||
This allows you to wrap up a source that has ``begin`` and ``end`` iterator-returning functions on it and return it as multiple results into Lua. To have more control over the returns, use :doc:`sol::variadic_results<variadic_results>`.
|
||||
|
||||
|
||||
.. code-block:: cpp
|
||||
.. literalinclude:: ../../../examples/as_returns.cpp
|
||||
:linenos:
|
||||
:caption: as_returns.c++
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
int main () {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", []() {
|
||||
std::set<std::string> results{ "arf", "bark", "woof" };
|
||||
return sol::as_returns(std::move(results));
|
||||
});
|
||||
|
||||
lua.script(R"(
|
||||
v1, v2, v3 = f()
|
||||
)");
|
||||
}());
|
||||
|
||||
std::string v1 = lua["v1"];
|
||||
std::string v2 = lua["v2"];
|
||||
std::string v3 = lua["v3"];
|
||||
|
||||
assert(v1 == "arf");
|
||||
assert(v2 == "bark");
|
||||
assert(v3 == "woof");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -13,13 +13,8 @@ as_table
|
||||
|
||||
This function serves the purpose of ensuring that an object is pushed -- if possible -- like a table into Lua. The container passed here can be a pointer, a reference, a ``std::reference_wrapper`` around a container, or just a plain container value. It must have a begin/end function, and if it has a ``std::pair<Key, Value>`` as its ``value_type``, it will be pushed as a dictionary. Otherwise, it's pushed as a sequence.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
lua.set("my_table", sol::as_table(std::vector<int>{ 1, 2, 3, 4, 5 }));
|
||||
lua.script("for k, v in ipairs(my_table) do print(k, v) assert(k == v) end");
|
||||
|
||||
.. literalinclude:: ../../../examples/docs/as_table_ipairs.cpp
|
||||
:linenos:
|
||||
|
||||
Note that any caveats with Lua tables apply the moment it is serialized, and the data cannot be gotten out back out in C++ as a C++ type. You can deserialize the Lua table into something explicitly using the ``sol::as_table_t`` marker for your get and conversion operations using Sol. At that point, the returned type is deserialized **from** a table, meaning you cannot reference any kind of C++ data directly as you do with regular userdata/usertypes. *All C++ type information is lost upon serialization into Lua.*
|
||||
|
||||
|
@ -11,7 +11,11 @@ c_call
|
||||
template <typename... Functions>
|
||||
int c_call (lua_State* L);
|
||||
|
||||
The goal of ``sol::c_call<...>`` is to provide a way to wrap a function and transport it through a compile-time context. This enables faster speed at the cost of a much harder to read / poorer interface, and can alleviate some template compilation speed issues. ``sol::c_call`` expects a type for its first template argument, and a value of the previously provided type for the second template argument. To make a compile-time transported overloaded function, specify multiple functions in the same ``type, value`` pairing, but put it inside of a ``sol::wrap``. Note that is can also be placed into the argument list for a :doc:`usertype<usertype>` as well.
|
||||
The goal of ``sol::c_call<...>`` is to provide a way to wrap a function and transport it through a compile-time context. This enables faster speed at the cost of a much harder to read / poorer interface, and can alleviate some template compilation speed issues. ``sol::c_call`` expects a type for its first template argument, and a value of the previously provided type for the second template argument. To make a compile-time transported overloaded function, specify multiple functions in the same ``type, value`` pairing, but put it inside of a ``sol::wrap``.
|
||||
|
||||
.. note::
|
||||
|
||||
This can also be placed into the argument list for a :doc:`usertype<usertype>` as well.
|
||||
|
||||
This pushes a raw ``lua_CFunction`` into whatever you pass the resulting ``c_call`` function pointer into, whether it be a table or a userdata or whatever else using sol2's API. The resulting ``lua_CFunction`` can also be used directly with the lua API, just like many of sol2's types can be intermingled with Lua's API if you know what you're doing.
|
||||
|
||||
@ -19,57 +23,7 @@ It is advisable for the user to consider making a macro to do the necessary ``de
|
||||
|
||||
Here's an example below of various ways to use ``sol::c_call``:
|
||||
|
||||
.. code-block:: cpp
|
||||
.. literalinclude:: ../../../examples/c_call.cpp
|
||||
:linenos:
|
||||
:caption: Compile-time transported function calls
|
||||
|
||||
#include "sol.hpp"
|
||||
|
||||
int f1(int) { return 32; }
|
||||
|
||||
int f2(int, int) { return 1; }
|
||||
|
||||
struct fer {
|
||||
double f3(int, int) {
|
||||
return 2.5;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
sol::state lua;
|
||||
// overloaded function f
|
||||
lua.set("f", sol::c_call<sol::wrap<decltype(&f1), &f1>, sol::wrap<decltype(&f2), &f2>, sol::wrap<decltype(&fer::f3), &fer::f3>>);
|
||||
// singly-wrapped function
|
||||
lua.set("g", sol::c_call<sol::wrap<decltype(&f1), &f1>>);
|
||||
// without the 'sol::wrap' boilerplate
|
||||
lua.set("h", sol::c_call<decltype(&f2), &f2>);
|
||||
// object used for the 'fer' member function call
|
||||
lua.set("obj", fer());
|
||||
|
||||
// call them like any other bound function
|
||||
lua.script("r1 = f(1)");
|
||||
lua.script("r2 = f(1, 2)");
|
||||
lua.script("r3 = f(obj, 1, 2)");
|
||||
lua.script("r4 = g(1)");
|
||||
lua.script("r5 = h(1, 2)");
|
||||
|
||||
// get the results and see
|
||||
// if it worked out
|
||||
int r1 = lua["r1"];
|
||||
// r1 == 32
|
||||
int r2 = lua["r2"];
|
||||
// r2 == 1
|
||||
double r3 = lua["r3"];
|
||||
// r3 == 2.5
|
||||
int r4 = lua["r4"];
|
||||
// r4 == 32
|
||||
int r5 = lua["r5"];
|
||||
// r5 == 1
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
.. _one similar to this: http://stackoverflow.com/a/5628222/5280922
|
||||
|
@ -1,6 +0,0 @@
|
||||
containers
|
||||
==========
|
||||
*for handling ``std::vector/map/set`` and others*
|
||||
|
||||
|
||||
See the full :doc:`containers documentation at the top level container page<../containers>`
|
@ -18,39 +18,8 @@ This type is passed to :ref:`sol::state(_view)::script/do_x<state-script-functio
|
||||
|
||||
There are many more uses, including storing state or special dependent variables in an environment that you pre-create using regular table opertions, and then changing at-will:
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: preparing environments
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
int main (int, char*[]) {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
sol::environment my_env(lua, sol::create);
|
||||
// set value, and we need to explicitly allow for
|
||||
// access to "print", since a new environment hides
|
||||
// everything that's not defined inside of it
|
||||
// NOTE: hiding also hides library functions (!!)
|
||||
// BE WARNED
|
||||
my_env["var"] = 50;
|
||||
my_env["print"] = lua["print"];
|
||||
|
||||
sol::environment my_other_env(lua, sol::create, lua.globals());
|
||||
// do not need to explicitly allow access to "print",
|
||||
// since we used the "Set a fallback" version
|
||||
// of the sol::environment constructor
|
||||
my_other_env["var"] = 443;
|
||||
|
||||
// output: 50
|
||||
lua.script("print(var)", my_env);
|
||||
|
||||
// output: 443
|
||||
lua.script("print(var)", my_other_env);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
.. literalinclude:: ../../../examples/docs/preparing_environments.cpp
|
||||
:linenos:
|
||||
|
||||
Also note that ``sol::environment`` derives from ``sol::table``, which also derives from ``sol::reference``: in other words, copying one ``sol::environment`` value to another ``sol::environment`` value **does not** deep-copy the table, just creates a new reference pointing to the same lua object.
|
||||
|
||||
|
@ -18,4 +18,4 @@ error
|
||||
|
||||
If an eror is thrown by Sol, it is going to be of this type. We use this in a single place: the default ``at_panic`` function we bind on construction of a :ref:`sol::state<set-panic>`. If you turn :doc:`off exceptions<../exceptions>`, the chances of you seeing this error are nil unless you specifically use it to pull errors out of things such as :doc:`sol::protected_function<protected_function>`.
|
||||
|
||||
As it derives from ``std::runtime_error``, which derives from ``std::exception``, you can catch it with a ``catch (const std::exception& )`` clause in your try/catch blocks. You can retrieve a string error from Lua (Lua pushes all its errors as string returns) by using this type with any of the get or lookup functions in Sol.
|
||||
As it derives from ``std::runtime_error``, which derives from ``std::exception``, you can catch it with a ``catch (const std::exception& )`` clause in your try/catch blocks. You can retrieve a string error from Lua (Lua pushes all its errors as string returns) by using this type with any of the get or lookup functions in Sol.
|
||||
|
@ -22,45 +22,25 @@ Function is a correct-assuming version of :doc:`protected_function<protected_fun
|
||||
|
||||
Calls the constructor and creates this type, straight from the stack. For example:
|
||||
|
||||
.. code-block:: lua
|
||||
:caption: func_barks.lua
|
||||
.. literalinclude:: ../../../examples/tie.cpp
|
||||
:caption: funcs.lua
|
||||
:lines: 7-11
|
||||
:linenos:
|
||||
|
||||
bark_power = 11;
|
||||
|
||||
function woof ( bark_energy )
|
||||
return (bark_energy * (bark_power / 4))
|
||||
end
|
||||
|
||||
The following C++ code will call this function from this file and retrieve the return value:
|
||||
|
||||
.. code-block:: cpp
|
||||
.. literalinclude:: ../../../examples/tie.cpp
|
||||
:lines: 16-22
|
||||
:linenos:
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.script_file( "func_barks.lua" );
|
||||
|
||||
sol::function woof = lua["woof"];
|
||||
double numwoof = woof(20);
|
||||
|
||||
The call ``woof(20)`` generates a :ref:`unsafe_function_result<unsafe-function-result>`, which is then implicitly converted to an ``double`` after being called. The intermediate temporary ``function_result`` is then destructed, popping the Lua function call results off the Lua stack.
|
||||
|
||||
You can also return multiple values by using ``std::tuple``, or if you need to bind them to pre-existing variables use ``sol::tie``:
|
||||
|
||||
.. code-block:: cpp
|
||||
.. literalinclude:: ../../../examples/tie.cpp
|
||||
:lines: 24-
|
||||
:linenos:
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.script( "function f () return 10, 11, 12 end" );
|
||||
|
||||
sol::function f = lua["f"];
|
||||
std::tuple<int, int, int> abc = f(); // 10, 11, 12 from Lua
|
||||
// or
|
||||
int a, b, c;
|
||||
sol::tie(a, b, c) = f(); // a = 10, b = 11, c = 12 from Lua
|
||||
|
||||
This makes it much easier to work with multiple return values. Using ``std::tie`` from the C++ standard will result in dangling references or bad behavior because of the very poor way in which C++ tuples/``std::tie`` were specified and implemented: please use ``sol::tie( ... )`` instead to satisfy any multi-return needs.
|
||||
|
||||
.. _function-result-warning:
|
||||
|
@ -10,145 +10,6 @@ metatable_key
|
||||
|
||||
You can use this in conjunction with :doc:`sol::table<table>` to set/get a metatable. Lua metatables are powerful ways to override default behavior of objects for various kinds of operators, among other things. Here is an entirely complete example, showing getting and working with a :doc:`usertype<usertype>`'s metatable defined by Sol:
|
||||
|
||||
.. code-block:: cpp
|
||||
.. literalinclude:: ../../../examples/metatable_key_low_level.cpp
|
||||
:caption: messing with metatables
|
||||
:linenos:
|
||||
|
||||
#include <sol.hpp>
|
||||
|
||||
int main () {
|
||||
|
||||
struct bark {
|
||||
int operator()(int x) {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<bark>("bark",
|
||||
sol::meta_function::call_function, &bark::operator()
|
||||
);
|
||||
|
||||
bark b;
|
||||
lua.set("b", &b);
|
||||
|
||||
sol::table b_as_table = lua["b"];
|
||||
sol::table b_metatable = b_as_table[sol::metatable_key];
|
||||
sol::function b_call = b_metatable["__call"];
|
||||
sol::function b_as_function = lua["b"];
|
||||
|
||||
int result1 = b_as_function(1);
|
||||
int result2 = b_call(b, 1);
|
||||
// result1 == result2 == 1
|
||||
}
|
||||
|
||||
It's further possible to have a "Dynamic Getter" (`thanks to billw2012 and Nava2 for this example`_!):
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: One way to make dynamic properties (there are others!)
|
||||
:linenos:
|
||||
|
||||
#include <sol.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
struct PropertySet {
|
||||
sol::object get_property_lua(const char* name, sol::this_state s)
|
||||
{
|
||||
auto& var = props[name];
|
||||
return sol::make_object(s, var);
|
||||
}
|
||||
|
||||
void set_property_lua(const char* name, sol::stack_object object)
|
||||
{
|
||||
props[name] = object.as<std::string>();
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> props;
|
||||
};
|
||||
|
||||
struct DynamicObject {
|
||||
PropertySet& get_dynamic_props() {
|
||||
return dynamic_props;
|
||||
}
|
||||
|
||||
PropertySet dynamic_props;
|
||||
};
|
||||
|
||||
|
||||
int main () {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<PropertySet>("PropertySet",
|
||||
sol::meta_function::new_index, &PropertySet::set_property_lua,
|
||||
sol::meta_function::index, &PropertySet::get_property_lua
|
||||
);
|
||||
|
||||
lua.new_usertype<DynamicObject>("DynamicObject",
|
||||
"props", sol::property(&DynamicObject::get_dynamic_props)
|
||||
);
|
||||
|
||||
lua.script(R"(
|
||||
obj = DynamicObject:new()
|
||||
obj.props.name = 'test name'
|
||||
print('name = ' .. obj.props.name)
|
||||
)");
|
||||
|
||||
std::string name = lua["obj"]["props"]["name"];
|
||||
// name == "test name";
|
||||
}
|
||||
|
||||
|
||||
You can even manipulate the ability to set and get items using metatable objects on a usertype or similar:
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: messing with metatables - vector type
|
||||
:linenos:
|
||||
|
||||
#include <sol.hpp>
|
||||
|
||||
class vector {
|
||||
public:
|
||||
double data[3];
|
||||
|
||||
vector() : data{ 0,0,0 } {}
|
||||
|
||||
double& operator[](int i)
|
||||
{
|
||||
return data[i];
|
||||
}
|
||||
|
||||
|
||||
static double my_index(vector& v, int i)
|
||||
{
|
||||
return v[i];
|
||||
}
|
||||
|
||||
static void my_new_index(vector& v, int i, double x)
|
||||
{
|
||||
v[i] = x;
|
||||
}
|
||||
};
|
||||
|
||||
int main () {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_usertype<vector>("vector", sol::constructors<sol::types<>>(),
|
||||
sol::meta_function::index, &vector::my_index,
|
||||
sol::meta_function::new_index, &vector::my_new_index);
|
||||
lua.script("v = vector.new()\n"
|
||||
"print(v[1])\n"
|
||||
"v[2] = 3\n"
|
||||
"print(v[2])\n"
|
||||
);
|
||||
|
||||
vector& v = lua["v"];
|
||||
// v[0] == 0.0;
|
||||
// v[1] == 0.0;
|
||||
// v[2] == 3.0;
|
||||
}
|
||||
|
||||
|
||||
.. _thanks to billw2012 and Nava2 for this example: https://github.com/ThePhD/sol2/issues/71#issuecomment-225402055
|
@ -10,7 +10,7 @@ nested
|
||||
};
|
||||
|
||||
|
||||
``sol::nested<...>`` is a template class similar to :doc:`sol::as_table<as_table>`, but with the caveat that every :doc:`container type<containers>` within the ``sol::nested`` type will be retrieved as a table from lua. This is helpful when you need to receive C++-style vectors, lists, and maps nested within each other: all of them will be deserialized from lua using table properties rather than anything else.
|
||||
``sol::nested<...>`` is a template class similar to :doc:`sol::as_table<as_table>`, but with the caveat that every :doc:`container type<../containers>` within the ``sol::nested`` type will be retrieved as a table from lua. This is helpful when you need to receive C++-style vectors, lists, and maps nested within each other: all of them will be deserialized from lua using table properties rather than anything else.
|
||||
|
||||
Note that any caveats with Lua tables apply the moment it is serialized, and the data cannot be gotten out back out in C++ as a C++ type. You can deserialize the Lua table into something explicitly using the ``sol::as_table_t`` marker for your get and conversion operations using Sol. At that point, the returned type is deserialized **from** a table, meaning you cannot reference any kind of C++ data directly as you do with regular userdata/usertypes. *All C++ type information is lost upon serialization into Lua.*
|
||||
|
||||
|
@ -7,15 +7,10 @@ new_table
|
||||
|
||||
struct new_table;
|
||||
|
||||
const new_table create = new_table{};
|
||||
constexpr const new_table create = new_table{};
|
||||
|
||||
``sol::new_table`` serves the purpose of letting you create tables using the constructor of :doc:`sol::table<table>` and :doc:`sol::environment<environment>`. It also disambiguates the other kinds of constructors, so is **necessary** to be specified. Leaving it off will result in the wrong constructor to be called, for either ``sol::table`` or ``sol::environment``.
|
||||
|
||||
There are two kinds of tables: the global table and non-global tables: however, both have the exact same interface and all ``sol::global_table`` s are convertible to regular ``sol::table`` s.
|
||||
|
||||
Tables are the core of Lua, and they are very much the core of Sol.
|
||||
|
||||
|
||||
members
|
||||
-------
|
||||
|
||||
|
@ -29,63 +29,21 @@ Its use is simple: wherever you can pass a function type to Lua, whether its on
|
||||
|
||||
The functions can be any kind of function / function object (lambda). Given these functions and struct:
|
||||
|
||||
.. code-block:: cpp
|
||||
.. literalinclude:: ../../../examples/overloading_with_members.cpp
|
||||
:linenos:
|
||||
|
||||
struct pup {
|
||||
int barks = 0;
|
||||
|
||||
void bark () {
|
||||
++barks; // bark!
|
||||
}
|
||||
|
||||
bool is_cute () const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void ultra_bark( pup& p, int barks) {
|
||||
for (; barks --> 0;) p.bark();
|
||||
}
|
||||
|
||||
void picky_bark( pup& p, std::string s) {
|
||||
if ( s == "bark" )
|
||||
p.bark();
|
||||
}
|
||||
:lines: 1-27
|
||||
|
||||
You then use it just like you would for any other part of the api:
|
||||
|
||||
.. code-block:: cpp
|
||||
.. literalinclude:: ../../../examples/overloading_with_members.cpp
|
||||
:linenos:
|
||||
:lines: 29-45
|
||||
|
||||
sol::state lua;
|
||||
Doing the following in Lua will call the specific overloads chosen, and their associated functions:
|
||||
|
||||
lua.set_function( "bark", sol::overload(
|
||||
ultra_bark,
|
||||
[]() { return "the bark from nowhere"; }
|
||||
) );
|
||||
|
||||
lua.new_usertype<pup>( "pup",
|
||||
// regular function
|
||||
"is_cute", &pup::is_cute,
|
||||
// overloaded function
|
||||
"bark", sol::overload( &pup::bark, &picky_bark )
|
||||
);
|
||||
|
||||
Thusly, doing the following in Lua:
|
||||
|
||||
.. code-block:: Lua
|
||||
:caption: pup.lua
|
||||
.. literalinclude:: ../../../examples/overloading_with_members.cpp
|
||||
:linenos:
|
||||
|
||||
local barker = pup.new()
|
||||
pup:bark() -- calls member function pup::bark
|
||||
pup:bark(20) -- calls ultra_bark
|
||||
pup:bark("meow") -- picky_bark, no bark
|
||||
pup:bark("bark") -- picky_bark, bark
|
||||
|
||||
bark(pup, 20) -- calls ultra_bark
|
||||
local nowherebark = bark() -- calls lambda which returns that string
|
||||
:lines: 47-
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -13,53 +13,6 @@ property
|
||||
|
||||
These set of functions create a type which allows a setter and getter pair (or a single getter, or a single setter) to be used to create a variable that is either read-write, read-only, or write-only. When used during :doc:`usertype<usertype>` construction, it will create a variable that uses the setter/getter member function specified.
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: player.hpp
|
||||
.. literalinclude:: ../../../examples/property.cpp
|
||||
:linenos:
|
||||
|
||||
class Player {
|
||||
public:
|
||||
int get_hp() const {
|
||||
return hp;
|
||||
}
|
||||
|
||||
void set_hp( int value ) {
|
||||
hp = value;
|
||||
}
|
||||
|
||||
int get_max_hp() const {
|
||||
return hp;
|
||||
}
|
||||
|
||||
void set_max_hp( int value ) {
|
||||
maxhp = value;
|
||||
}
|
||||
|
||||
private:
|
||||
int hp = 50;
|
||||
int maxHp = 50;
|
||||
}
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: game.cpp
|
||||
:linenos:
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set("theplayer", Player());
|
||||
|
||||
// Yes, you can register after you set a value and it will
|
||||
// connect up the usertype automatically
|
||||
lua.new_usertype<Player>( "Player",
|
||||
"hp", sol::property(&Player::get_hp, &Player::set_hp),
|
||||
"maxHp", sol::property(&Player::get_max_hp, &Player::set_max_hp)
|
||||
);
|
||||
|
||||
|
||||
.. code-block:: lua
|
||||
:caption: game-snippet.lua
|
||||
|
||||
-- variable syntax, calls functions
|
||||
theplayer.hp = 20
|
||||
print(theplayer.hp)
|
@ -10,24 +10,5 @@ protect
|
||||
|
||||
``sol::protect( my_func )`` allows you to protect a function call or member variable call when it is being set to Lua. It can be used with usertypes or when just setting a function into Sol. Below is an example that demonstrates that a call that would normally not error without :doc:`Safety features turned on<../safety>` that instead errors and makes the Lua safety-call wrapper ``pcall`` fail:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
struct protect_me {
|
||||
int gen(int x) {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_usertype<protect_me>("protect_me",
|
||||
"gen", sol::protect( &protect_me::gen )
|
||||
);
|
||||
|
||||
lua.script(R"__(
|
||||
pm = protect_me.new()
|
||||
value = pcall(pm.gen,pm)
|
||||
)__");
|
||||
);
|
||||
bool value = lua["value"];
|
||||
// value == false
|
||||
.. literalinclude:: ../../../examples/protect.cpp
|
||||
:linenos:
|
||||
|
@ -42,7 +42,7 @@ The following C++ code will call this function from this file and retrieve the r
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.open_file( "pfunc_barks.lua" );
|
||||
lua.script_file( "pfunc_barks.lua" );
|
||||
|
||||
sol::protected_function problematicwoof = lua["woof"];
|
||||
problematicwoof.error_handler = lua["got_problems"];
|
||||
@ -81,7 +81,7 @@ Alternatively, with a bad or good function call, you can use ``sol::optional`` t
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.open_file( "pfunc_barks.lua" );
|
||||
lua.script_file( "pfunc_barks.lua" );
|
||||
|
||||
sol::protected_function problematicwoof = lua["woof"];
|
||||
problematicwoof.error_handler = lua["got_problems"];
|
||||
@ -104,7 +104,7 @@ If you're confident the result succeeded, you can also just put the type you wan
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.open_file( "pfunc_barks.lua" );
|
||||
lua.script_file( "pfunc_barks.lua" );
|
||||
|
||||
// construct with function + error handler
|
||||
// shorter than old syntax
|
||||
@ -121,7 +121,7 @@ Finally, it is *important* to note you can set a default handler. The function i
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.open_file( "pfunc_barks.lua" );
|
||||
lua.script_file( "pfunc_barks.lua" );
|
||||
// sets got_problems as the default
|
||||
// handler for all protected_function errors
|
||||
sol::protected_function::set_default_handler(lua["got_problems"]);
|
||||
|
@ -14,56 +14,8 @@ The goal of read-only is to protect a variable set on a usertype or a function.
|
||||
If you are looking to make a read-only table, you need to go through a bit of a complicated song and dance by overriding the ``__index`` metamethod. Here's a complete example on the way to do that using ``sol``:
|
||||
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: read-only.cpp
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
struct object {
|
||||
void my_func() {
|
||||
std::cout << "hello\n";
|
||||
}
|
||||
};
|
||||
|
||||
int deny(lua_State* L) {
|
||||
return luaL_error(L, "HAH! Deniiiiied!");
|
||||
}
|
||||
|
||||
int main() {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
object my_obj;
|
||||
|
||||
sol::table obj_table = lua.create_named_table("object");
|
||||
|
||||
sol::table obj_metatable = lua.create_table_with();
|
||||
obj_metatable.set_function("my_func", &object::my_func, &my_obj);
|
||||
// Set whatever else you need to
|
||||
// on the obj_metatable,
|
||||
// not on the obj_table itself!
|
||||
|
||||
// Properly self-index metatable to block things
|
||||
obj_metatable[sol::meta_function::new_index] = deny;
|
||||
obj_metatable[sol::meta_function::index] = obj_metatable;
|
||||
|
||||
// Set it on the actual table
|
||||
obj_table[sol::metatable_key] = obj_metatable;
|
||||
|
||||
try {
|
||||
lua.script(R"(
|
||||
print(object.my_func)
|
||||
object["my_func"] = 24
|
||||
print(object.my_func)
|
||||
)");
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
.. literalinclude:: ../../../examples/read_only.cpp
|
||||
:caption: read_only.cpp
|
||||
:linenos:
|
||||
|
||||
It is a verbose example, but it explains everything. Because the process is a bit involved and can have unexpected consequences for users that make their own tables, making read-only tables is something that we ask the users to do themselves with the above code, as getting the semantics right for the dozens of use cases would be tremendously difficult.
|
||||
|
@ -17,43 +17,12 @@ This type is particular to working with the stack. It does not push the function
|
||||
|
||||
Furthermore, if you know you have a function in the right place alongside proper arguments on top of it, you can use the ``sol::stack_count`` structure and give its constructor the number of arguments off the top that you want to call your pre-prepared function with:
|
||||
|
||||
.. code-block:: cpp
|
||||
.. literalinclude:: ../../../examples/stack_aligned_function.cpp
|
||||
:caption: stack_aligned_function.cpp
|
||||
:linenos:
|
||||
:name: stack-top-example
|
||||
:name: stack-aligned-function-example
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
int main (int, char*[]) {
|
||||
sol::state lua;
|
||||
lua.set_function("func", [](int a, int b) { return (a + b) * 2;});
|
||||
|
||||
sol::reference func_ref = lua["func"];
|
||||
lua_State* L = lua.lua_state();
|
||||
|
||||
// for some reason, you need to use the low-level API
|
||||
func_ref.push(); // function on stack now
|
||||
|
||||
// maybe this is in a lua_CFunction you bind,
|
||||
// or maybe you're trying to work with a pre-existing system
|
||||
sol::stack_aligned_function func(L, -1);
|
||||
lua_pushinteger(L, 5); // argument 1
|
||||
lua_pushinteger(L, 6); // argument 2
|
||||
// take 2 arguments from the top,
|
||||
// and use "stack_aligned_function" to call
|
||||
int result = func(sol::stack_count(2));
|
||||
|
||||
// make sure everything is clean
|
||||
assert(result == 22);
|
||||
assert(lua.stack_top() == 0); // stack is empty/balanced
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Finally, there is a special abstraction that provides further stack optimizations for ``sol::protected_function`` variants that are aligned, and it is called ``sol::stack_aligned_stack_handler_protected_function``. This typedef expects you to pass a ``stack_reference`` handler to its constructor, meaning that you have already placed an appropriate error-handling function somewhere on the stack before the aligned function. You can use ``sol::stack_count`` with this type as well,
|
||||
Finally, there is a special abstraction that provides further stack optimizations for ``sol::protected_function`` variants that are aligned, and it is called ``sol::stack_aligned_stack_handler_protected_function``. This typedef expects you to pass a ``stack_reference`` handler to its constructor, meaning that you have already placed an appropriate error-handling function somewhere on the stack before the aligned function. You can use ``sol::stack_count`` with this type as well.
|
||||
|
||||
.. warning::
|
||||
|
||||
|
@ -85,6 +85,8 @@ These functions set items into the table. The first one (``set``) can set *mult
|
||||
|
||||
If the keys within nested queries try to traverse into a table that doesn't exist, it will first pull out a ``nil`` value. If there are further lookups past a key that do not exist, the additional lookups into the nil-returned variable will cause a panic to be fired by the lua C API.
|
||||
|
||||
Please note how callables and lambdas are serialized, as there may be issues on GCC-based implementations. See this :ref:`note here<lambda-registry>`.
|
||||
|
||||
This function does not create tables where they do not exist.
|
||||
|
||||
.. code-block:: cpp
|
||||
@ -99,6 +101,8 @@ This function does not create tables where they do not exist.
|
||||
|
||||
Similar to :ref:`set<set-value>`, but it does so "raw" (ignoring metamethods on the table's metatable).
|
||||
|
||||
Please note how callables and lambdas are serialized, as there may be issues on GCC-based implementations. See this :ref:`note here<lambda-registry>`.
|
||||
|
||||
.. note::
|
||||
|
||||
Value semantics are applied to all set operations. If you do not ``std::ref( obj )`` or specifically make a pointer with ``std::addressof( obj )`` or ``&obj``, it will copy / move. This is different from how :doc:`sol::function<function>` behaves with its call operator. Also note that this does not detect callables by default: see the :ref:`note here<binding-callable-objects>`.
|
||||
@ -220,6 +224,8 @@ A functional ``for_each`` loop that calls the desired function. The passed in fu
|
||||
|
||||
Generates a :doc:`proxy<proxy>` that is templated on the table type and the key type. Enables lookup of items and their implicit conversion to a desired type. Lookup is done lazily.
|
||||
|
||||
Please note how callables and lambdas are serialized, as there may be issues on GCC-based implementations. See this :ref:`note here<lambda-registry>`.
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: function: create a table with defaults
|
||||
:name: table-create
|
||||
@ -256,4 +262,4 @@ Creates a table, optionally with the specified values pre-set into the table. It
|
||||
|
||||
Creates a table, optionally with the specified values pre-set into the table, and sets it as the key ``name`` in the table. Applies the same rules as :ref:`table.set<set-value>` when putting the argument values into the table, including how it handles callable objects.
|
||||
|
||||
.. _input iterators: http://en.cppreference.com/w/cpp/concept/InputIterator
|
||||
.. _input iterators: http://en.cppreference.com/w/cpp/concept/InputIterator
|
||||
|
@ -5,22 +5,7 @@ tie
|
||||
|
||||
`std::tie()`_ does not work well with :doc:`sol::function<function>`'s ``sol::function_result`` returns. Use ``sol::tie`` instead. Because they're both named `tie`, you'll need to be explicit when you use Sol's by naming it with the namespace (``sol::tie``), even with a ``using namespace sol;``. Here's an example:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
const auto& code = R"(
|
||||
function test()
|
||||
return 1, 2, 3
|
||||
end
|
||||
)";
|
||||
lua.script(code);
|
||||
|
||||
int a, b, c;
|
||||
//std::tie(a, b, c) = lua["test"]();
|
||||
// will error: use the line below
|
||||
sol::tie(a, b, c) = lua["test"]();
|
||||
|
||||
.. literalinclude:: ../../../examples/tie.cpp
|
||||
:linenos:
|
||||
|
||||
.. _std::tie(): http://en.cppreference.com/w/cpp/utility/tuple/tie
|
||||
|
@ -69,9 +69,9 @@ Equivalently, you can also write:
|
||||
);
|
||||
|
||||
// set usertype explicitly, with the given name
|
||||
lua.set_usertype<ship>( "ship", shiptype );
|
||||
lua.set_usertype( "ship", shiptype );
|
||||
|
||||
// shiptype is now a useless skeleton type, just let it destruct naturally and don't use it again.
|
||||
// the shiptype variable is now a useless skeleton type, just let it destruct naturally and don't use it again.
|
||||
|
||||
|
||||
Note that here, because the C++ class is default-constructible, it will automatically generate a creation function that can be called in lua called "new" that takes no arguments. You can use it like this in lua code:
|
||||
@ -285,39 +285,17 @@ usertype arguments - simple usertype
|
||||
- Should probably not be used directly. Use ``sol::table::new_usertype`` or ``sol::table::new_simple_usertype`` instead
|
||||
|
||||
|
||||
|
||||
|
||||
runtime functions
|
||||
-----------------
|
||||
|
||||
You can add functions at runtime **to the whole class** (not to individual objects). Set a name under the metatable name you bound using ``new_usertype``/``new_simple_usertype`` to an object. For example:
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
.. literalinclude:: ../../../examples/docs/runtime_extension.cpp
|
||||
:caption: runtime_extension.cpp
|
||||
:name: runtime-extension
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
struct object {
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
int main (int, char*[]) {
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<object>( "object" );
|
||||
|
||||
// runtime additions: through the sol API
|
||||
lua["object"]["func"] = [](object& o) { return o.value; };
|
||||
// runtime additions: through a lua script
|
||||
lua.script("function object:print () print(self:func()) end");
|
||||
|
||||
// see it work
|
||||
lua.script("local obj = object.new() \n obj:print()");
|
||||
}
|
||||
|
||||
:name: runtime-extension-example
|
||||
:linenos:
|
||||
|
||||
.. note::
|
||||
|
||||
@ -341,35 +319,18 @@ If your class has no complicated™ virtual inheritance or multiple inheritance,
|
||||
|
||||
For the rest of us safe individuals out there: You must specify the ``sol::base_classes`` tag with the ``sol::bases<Types...>()`` argument, where ``Types...`` are all the base classes of the single type ``T`` that you are making a usertype out of.
|
||||
|
||||
Register the base classes explicitly.
|
||||
|
||||
.. note::
|
||||
|
||||
Always specify your bases if you plan to retrieve a base class using the Sol abstraction directly and not casting yourself.
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
|
||||
struct A {
|
||||
int a = 10;
|
||||
virtual int call() { return 0; }
|
||||
};
|
||||
struct B : A {
|
||||
int b = 11;
|
||||
virtual int call() override { return 20; }
|
||||
};
|
||||
|
||||
Then, to register the base classes explicitly:
|
||||
|
||||
.. code-block:: cpp
|
||||
.. literalinclude:: ../../../examples/docs/inheritance.cpp
|
||||
:caption: inheritance.cpp
|
||||
:name: inheritance-example
|
||||
:linenos:
|
||||
:emphasize-lines: 5
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.new_usertype<B>( "B",
|
||||
"call", &B::call,
|
||||
sol::base_classes, sol::bases<A>()
|
||||
);
|
||||
|
||||
.. note::
|
||||
|
||||
You must list ALL base classes, including (if there were any) the base classes of A, and the base classes of those base classes, etc. if you want Sol/Lua to handle them automagically.
|
||||
|
@ -12,7 +12,7 @@ Containers are objects that are meant to be inspected and iterated and whose job
|
||||
* This means containers **do not automatically serialize as Lua tables**
|
||||
- If you need tables, consider using ``sol::as_table`` and ``sol::nested``
|
||||
- See `this table serialization example`_ for more details
|
||||
* Lua 5.1 has different semantics for ``pairs`` and ``ipairs``: see the example for plain containers in the :doc:`api documentation page for containers<api/containers>`
|
||||
* Lua 5.1 has different semantics for ``pairs`` and ``ipairs``: be wary. See :ref:`examples down below<containers-pairs-example>` for more details
|
||||
* You can override container behavior by overriding :ref:`the detection trait<container-detection>` and :ref:`specializing the container_traits template<container-traits>`
|
||||
* You can bind typical C-style arrays, but must follow :ref:`the rules<container-c-array>`
|
||||
|
||||
@ -232,7 +232,7 @@ Note that this will not work well in Lua 5.1, as it has explicit table checks an
|
||||
|
||||
There are also other ways to iterate over key/values, but they can be difficult AND cost your performance due to not having proper support in Lua 5.1. We recommend that you upgrade to Lua 5.2 or 5.3 if this is integral to your infrastructure.
|
||||
|
||||
If you can't upgrade, use the member-function ``my_container:pairs()`` in Lua to perform iteration:
|
||||
If you can't upgrade, use the "member" function ``my_container:pairs()`` in Lua to perform iteration:
|
||||
|
||||
.. literalinclude:: ../../examples/container_with_pairs.cpp
|
||||
:name: containers-pairs-example
|
||||
|
@ -29,7 +29,15 @@ There are a number of examples dealing with functions and how they can be bound
|
||||
working with callables/lambdas
|
||||
------------------------------
|
||||
|
||||
To be explicit about wanting a struct to be interpreted as a function, use ``mytable.set_function( key, func_value );``. You can also use the :doc:`sol::as_function<../api/as_function>` call, which will wrap and identify your type as a function.
|
||||
To be explicit about wanting a struct to be interpreted as a function, use ``my_table.set_function( key, func_value );``. You can also use the :doc:`sol::as_function<../api/as_function>` call, which will wrap and identify your type as a function.
|
||||
|
||||
.. _lambda-registry:
|
||||
.. note::
|
||||
|
||||
When you set lambdas/callables through ``my_table.set( ... )`` using the same function signature, you can suffer from ``const static`` data (like string literals) from not "behaving properly". This is because some compilers do not provide unique type names that we can get at in C++ with RTTI disabled, and thusly it will register the first lambda of the specific signature as the one that will be called. The result is that string literals and other data stored in an compiler implementation-defined manner might be folded and the wrong routine run, even if other observable side effects are nice.
|
||||
|
||||
To avoid this problem, register all your lambdas with :ref:`my_table.set_function<set-function>` and `avoid the nightmare altogether`_.
|
||||
|
||||
|
||||
Furthermore, it is important to know that lambdas without a specified return type (and a non-const, non-reference-qualified ``auto``) will decay return values. To capture or return references explicitly, use ``decltype(auto)`` or specify the return type **exactly** as desired:
|
||||
|
||||
@ -37,7 +45,6 @@ Furthermore, it is important to know that lambdas without a specified return typ
|
||||
:name: refereces-in-lambdas-example
|
||||
:linenos:
|
||||
|
||||
|
||||
.. _function-exception-handling:
|
||||
|
||||
exception safety/handling
|
||||
@ -97,3 +104,4 @@ Note that stateless lambdas can be converted to a function pointer, so stateless
|
||||
|
||||
|
||||
.. _the examples: https://github.com/ThePhD/sol2/blob/develop/examples/functions.cpp
|
||||
.. _avoid the nightmare altogether: https://github.com/ThePhD/sol2/issues/608#issuecomment-372876206
|
||||
|
@ -26,6 +26,14 @@ The examples folder also has a number of really great examples for you to see. T
|
||||
* (Advanced) You can override the iteration function for Lua 5.2 and above (LuaJIT does not have the capability) `as shown in the pairs example`_
|
||||
* (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
|
||||
|
||||
.. _usertype-special-features:
|
||||
.. note::
|
||||
|
||||
Note that to use many of sol2'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:
|
||||
|
||||
* Please note that the colon is necessary to "automatically" pass the ``this``/``self`` argument to Lua methods
|
||||
- ``obj:method_name()`` is how you call "member" methods in Lua
|
||||
- It is purely syntactic sugar that passes the object name as the first argument to the ``method_name`` function
|
||||
|
@ -39,7 +39,7 @@ int main() {
|
||||
// result3 == 16.5
|
||||
c_assert(result3 == 16.5);
|
||||
|
||||
std::cout << "=== any_return example ===" << std::endl;
|
||||
std::cout << "=== any_return ===" << std::endl;
|
||||
std::cout << "result : " << result << std::endl;
|
||||
std::cout << "result2: " << result2 << std::endl;
|
||||
std::cout << "result3: " << result3 << std::endl;
|
||||
|
31
examples/args_from_container.cpp
Normal file
31
examples/args_from_container.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
int main(int , const char*[]) {
|
||||
|
||||
std::cout << "=== args_from_container ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
lua.script("function f (a, b, c, d) print(a, b, c, d) end");
|
||||
|
||||
sol::function f = lua["f"];
|
||||
|
||||
std::vector<int> v2{ 3, 4 };
|
||||
f(1, 2, sol::as_args(v2));
|
||||
|
||||
std::set<int> v4{ 3, 1, 2, 4 };
|
||||
f(sol::as_args(v4));
|
||||
|
||||
int v3[] = { 2, 3, 4 };
|
||||
f(1, sol::as_args(v3));
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
28
examples/as_returns.cpp
Normal file
28
examples/as_returns.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
int main () {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", []() {
|
||||
std::set<std::string> results{ "arf", "bark", "woof" };
|
||||
return sol::as_returns(std::move(results));
|
||||
});
|
||||
|
||||
lua.script("v1, v2, v3 = f()");
|
||||
|
||||
std::string v1 = lua["v1"];
|
||||
std::string v2 = lua["v2"];
|
||||
std::string v3 = lua["v3"];
|
||||
|
||||
c_assert(v1 == "arf");
|
||||
c_assert(v2 == "bark");
|
||||
c_assert(v3 == "woof");
|
||||
|
||||
return 0;
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
#include "assert.hpp"
|
||||
|
||||
int main() {
|
||||
std::cout << "=== basic example ===" << std::endl;
|
||||
std::cout << "=== basic ===" << std::endl;
|
||||
// create an empty lua state
|
||||
sol::state lua;
|
||||
|
||||
|
50
examples/c_call.cpp
Normal file
50
examples/c_call.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
int f1(int) { return 32; }
|
||||
|
||||
int f2(int, int) { return 1; }
|
||||
|
||||
struct fer {
|
||||
double f3(int, int) {
|
||||
return 2.5;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
sol::state lua;
|
||||
// overloaded function f
|
||||
lua.set("f", sol::c_call<sol::wrap<decltype(&f1), &f1>, sol::wrap<decltype(&f2), &f2>, sol::wrap<decltype(&fer::f3), &fer::f3>>);
|
||||
// singly-wrapped function
|
||||
lua.set("g", sol::c_call<sol::wrap<decltype(&f1), &f1>>);
|
||||
// without the 'sol::wrap' boilerplate
|
||||
lua.set("h", sol::c_call<decltype(&f2), &f2>);
|
||||
// object used for the 'fer' member function call
|
||||
lua.set("obj", fer());
|
||||
|
||||
// call them like any other bound function
|
||||
lua.script("r1 = f(1)");
|
||||
lua.script("r2 = f(1, 2)");
|
||||
lua.script("r3 = f(obj, 1, 2)");
|
||||
lua.script("r4 = g(1)");
|
||||
lua.script("r5 = h(1, 2)");
|
||||
|
||||
// get the results and see
|
||||
// if it worked out
|
||||
int r1 = lua["r1"];
|
||||
c_assert(r1 == 32);
|
||||
int r2 = lua["r2"];
|
||||
c_assert(r2 == 1);
|
||||
double r3 = lua["r3"];
|
||||
c_assert(r3 == 2.5);
|
||||
int r4 = lua["r4"];
|
||||
c_assert(r4 == 32);
|
||||
int r5 = lua["r5"];
|
||||
c_assert(r5 == 1);
|
||||
|
||||
return 0;
|
||||
}
|
@ -23,7 +23,7 @@ sol::variadic_results fallback(sol::this_state ts, sol::variadic_args args) {
|
||||
}
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== calling lua functions example ===" << std::endl;
|
||||
std::cout << "=== calling lua functions ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
@ -36,7 +36,7 @@ height = 1080
|
||||
c_assert(screen.width == 1920);
|
||||
c_assert(screen.height == 1080);
|
||||
|
||||
std::cout << "=== config example ===" << std::endl;
|
||||
std::cout << "=== config ===" << std::endl;
|
||||
screen.print();
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ namespace sol {
|
||||
}
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== container as container example ===" << std::endl;
|
||||
std::cout << "=== container as container ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -18,7 +18,7 @@ int main() {
|
||||
|
||||
using my_set = std::unordered_set<std::pair<std::string, std::string>, hasher>;
|
||||
|
||||
std::cout << "=== containers with std::pair<> example ===" << std::endl;
|
||||
std::cout << "=== containers with std::pair<> ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int, char**) {
|
||||
std::cout << "=== containers example ===" << std::endl;
|
||||
std::cout << "=== containers ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
@ -54,7 +54,7 @@ void demo_explicit (sol::as_table_t<std::map<std::string, sol::as_table_t<std::v
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
std::cout << "=== containers retrieved from lua tables example ===" << std::endl;
|
||||
std::cout << "=== containers retrieved from lua tables ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
// bind the function
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "=== coroutine example ===" << std::endl;
|
||||
std::cout << "=== coroutine ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
std::vector<sol::coroutine> tasks;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== coroutine state transfer example ===" << std::endl;
|
||||
std::cout << "=== coroutine state transfer ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
@ -72,7 +72,7 @@ namespace sol {
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "=== customization example ===" << std::endl;
|
||||
std::cout << "=== customization ===" << std::endl;
|
||||
std::cout << std::boolalpha;
|
||||
|
||||
sol::state lua;
|
||||
|
21
examples/docs/as_function.cpp
Normal file
21
examples/docs/as_function.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
int main () {
|
||||
struct callable {
|
||||
int operator()( int a, bool b ) {
|
||||
return a + b ? 10 : 20;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
sol::state lua;
|
||||
// Binds struct as userdata
|
||||
// can still be callable, but beware
|
||||
// caveats
|
||||
lua.set( "not_func", callable() );
|
||||
// Binds struct as function
|
||||
lua.set( "func", sol::as_function( callable() ) );
|
||||
// equivalent: lua.set_function( "func", callable() );
|
||||
// equivalent: lua["func"] = callable();
|
||||
}
|
27
examples/docs/as_function_usertype_member_variable.cpp
Normal file
27
examples/docs/as_function_usertype_member_variable.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
int main () {
|
||||
class B {
|
||||
public:
|
||||
int bvar = 24;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
lua.new_usertype<B>("B",
|
||||
// bind as variable
|
||||
"b", &B::bvar,
|
||||
// bind as function
|
||||
"f", sol::as_function(&B::bvar)
|
||||
);
|
||||
|
||||
B b;
|
||||
lua.set("b", &b);
|
||||
lua.script("x = b:f()");
|
||||
lua.script("y = b.b");
|
||||
int x = lua["x"];
|
||||
int y = lua["y"];
|
||||
assert(x == 24);
|
||||
assert(y == 24);
|
||||
}
|
14
examples/docs/as_table_ipairs.cpp
Normal file
14
examples/docs/as_table_ipairs.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
int main (int, char*[]) {
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
lua.set("my_table", sol::as_table(std::vector<int>{ 1, 2, 3, 4, 5 }));
|
||||
lua.script("for k, v in ipairs(my_table) do print(k, v) assert(k == v) end");
|
||||
|
||||
return 0;
|
||||
}
|
27
examples/docs/inheritance.cpp
Normal file
27
examples/docs/inheritance.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
struct A {
|
||||
int a = 10;
|
||||
virtual int call() { return 0; }
|
||||
};
|
||||
struct B : A {
|
||||
int b = 11;
|
||||
virtual int call() override { return 20; }
|
||||
};
|
||||
|
||||
int main (int, char*[]) {
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.new_usertype<B>( "A",
|
||||
"call", &A::call
|
||||
);
|
||||
|
||||
lua.new_usertype<B>( "B",
|
||||
"call", &B::call,
|
||||
sol::base_classes, sol::bases<A>()
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
29
examples/docs/preparing_environments.cpp
Normal file
29
examples/docs/preparing_environments.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
int main (int, char*[]) {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
sol::environment my_env(lua, sol::create);
|
||||
// set value, and we need to explicitly allow for
|
||||
// access to "print", since a new environment hides
|
||||
// everything that's not defined inside of it
|
||||
// NOTE: hiding also hides library functions (!!)
|
||||
// BE WARNED
|
||||
my_env["var"] = 50;
|
||||
my_env["print"] = lua["print"];
|
||||
|
||||
sol::environment my_other_env(lua, sol::create, lua.globals());
|
||||
// do not need to explicitly allow access to "print",
|
||||
// since we used the "Set a fallback" version
|
||||
// of the sol::environment constructor
|
||||
my_other_env["var"] = 443;
|
||||
|
||||
// output: 50
|
||||
lua.script("print(var)", my_env);
|
||||
|
||||
// output: 443
|
||||
lua.script("print(var)", my_other_env);
|
||||
|
||||
return 0;
|
||||
}
|
28
examples/docs/runtime_extension.cpp
Normal file
28
examples/docs/runtime_extension.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
struct object {
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
int main (int, char*[]) {
|
||||
|
||||
std::cout << "==== runtime_extension =====" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<object>( "object" );
|
||||
|
||||
// runtime additions: through the sol API
|
||||
lua["object"]["func"] = [](object& o) { return o.value; };
|
||||
// runtime additions: through a lua script
|
||||
lua.script("function object:print () print(self:func()) end");
|
||||
|
||||
// see it work
|
||||
lua.script("local obj = object.new() \n obj:print()");
|
||||
|
||||
return 0;
|
||||
}
|
@ -33,7 +33,7 @@ struct dynamic_object {
|
||||
|
||||
|
||||
int main() {
|
||||
std::cout << "=== dynamic_object example ===" << std::endl;
|
||||
std::cout << "=== dynamic_object ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -70,7 +70,7 @@ void complicated(sol::this_state ts) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "=== environment snooping example ===" << std::endl;
|
||||
std::cout << "=== environment snooping ===" << std::endl;
|
||||
sol::state lua;
|
||||
|
||||
sol::environment freshenv(lua, sol::create, lua.globals());
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== environment state example ===" << std::endl;
|
||||
std::cout << "=== environment state ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int, char* []) {
|
||||
std::cout << "=== environment state 2 example ===" << std::endl;
|
||||
std::cout << "=== environment state 2 ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
@ -21,7 +21,7 @@ void test_environment(std::string key, const sol::environment& env, const sol::s
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
std::cout << "=== environments example ===" << std::endl;
|
||||
std::cout << "=== environments ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
// A global variable to see if we can "fallback" into it
|
||||
|
@ -33,7 +33,7 @@ void will_throw() {
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "=== exception_handler example ===" << std::endl;
|
||||
std::cout << "=== exception_handler ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -19,7 +19,7 @@ struct multiplier {
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== functions example ===" << std::endl;
|
||||
std::cout << "=== functions ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
44
examples/index_and_newindex_usertype.cpp
Normal file
44
examples/index_and_newindex_usertype.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
class vector {
|
||||
public:
|
||||
double data[3];
|
||||
|
||||
vector() : data{ 0,0,0 } {}
|
||||
|
||||
double& operator[](int i) {
|
||||
return data[i];
|
||||
}
|
||||
|
||||
|
||||
static double my_index(vector& v, int i) {
|
||||
return v[i];
|
||||
}
|
||||
|
||||
static void my_new_index(vector& v, int i, double x) {
|
||||
v[i] = x;
|
||||
}
|
||||
};
|
||||
|
||||
int main () {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_usertype<vector>("vector", sol::constructors<sol::types<>>(),
|
||||
sol::meta_function::index, &vector::my_index,
|
||||
sol::meta_function::new_index, &vector::my_new_index);
|
||||
lua.script("v = vector.new()\n"
|
||||
"print(v[1])\n"
|
||||
"v[2] = 3\n"
|
||||
"print(v[2])\n"
|
||||
);
|
||||
|
||||
vector& v = lua["v"];
|
||||
c_assert(v[0] == 0.0);
|
||||
c_assert(v[1] == 0.0);
|
||||
c_assert(v[2] == 3.0);
|
||||
|
||||
return 0;
|
||||
}
|
@ -34,7 +34,7 @@ sol::variadic_results call_it(sol::object function_name, sol::variadic_args args
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "=== indirect function calls example ===" << std::endl;
|
||||
std::cout << "=== indirect function calls ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
35
examples/metatable_key_low_level.cpp
Normal file
35
examples/metatable_key_low_level.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
int main () {
|
||||
|
||||
struct bark {
|
||||
int operator()(int x) {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<bark>("bark",
|
||||
sol::meta_function::call_function, &bark::operator()
|
||||
);
|
||||
|
||||
bark b;
|
||||
lua.set("b", &b);
|
||||
|
||||
sol::table b_as_table = lua["b"];
|
||||
sol::table b_metatable = b_as_table[sol::metatable_key];
|
||||
sol::function b_call = b_metatable["__call"];
|
||||
sol::function b_as_function = lua["b"];
|
||||
|
||||
int result1 = b_as_function(1);
|
||||
// pass 'self' directly to argument
|
||||
int result2 = b_call(b, 1);
|
||||
c_assert(result1 == result2);
|
||||
c_assert(result1 == 1);
|
||||
c_assert(result2 == 1);
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "=== multi results example ===" << std::endl;
|
||||
std::cout << "=== multi results ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int, char**) {
|
||||
std::cout << "=== optional with iteration example ===" << std::endl;
|
||||
std::cout << "=== optional with iteration ===" << std::endl;
|
||||
|
||||
struct thing {
|
||||
int a = 20;
|
||||
|
@ -13,7 +13,7 @@ inline std::string make_string(std::string input) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "=== overloading example ===" << std::endl;
|
||||
std::cout << "=== overloading ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -23,7 +23,7 @@ sol::variadic_results fallback(sol::this_state ts, sol::variadic_args args) {
|
||||
}
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== overloading with fallback example ===" << std::endl;
|
||||
std::cout << "=== overloading with fallback ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
66
examples/overloading_with_members.cpp
Normal file
66
examples/overloading_with_members.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
struct pup {
|
||||
int barks = 0;
|
||||
|
||||
void bark () {
|
||||
++barks; // bark!
|
||||
}
|
||||
|
||||
bool is_cute () const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void ultra_bark( pup& p, int barks) {
|
||||
for (; barks --> 0;) p.bark();
|
||||
}
|
||||
|
||||
void picky_bark( pup& p, std::string s) {
|
||||
if ( s == "bark" )
|
||||
p.bark();
|
||||
}
|
||||
|
||||
int main () {
|
||||
std::cout << "=== overloading with members ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function( "bark", sol::overload(
|
||||
ultra_bark,
|
||||
[]() { return "the bark from nowhere"; }
|
||||
) );
|
||||
|
||||
lua.new_usertype<pup>( "pup",
|
||||
// regular function
|
||||
"is_cute", &pup::is_cute,
|
||||
// overloaded function
|
||||
"bark", sol::overload( &pup::bark, &picky_bark )
|
||||
);
|
||||
|
||||
const auto& code = R"(
|
||||
barker = pup.new()
|
||||
print(barker:is_cute())
|
||||
barker:bark() -- calls member function pup::bark
|
||||
barker:bark("meow") -- picky_bark, no bark
|
||||
barker:bark("bark") -- picky_bark, bark
|
||||
|
||||
bark(barker, 20) -- calls ultra_bark
|
||||
print(bark()) -- calls lambda which returns that string
|
||||
)";
|
||||
|
||||
lua.script(code);
|
||||
|
||||
pup& barker = lua["barker"];
|
||||
std::cout << barker.barks << std::endl;
|
||||
c_assert(barker.barks == 22);
|
||||
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
57
examples/property.cpp
Normal file
57
examples/property.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class Player {
|
||||
public:
|
||||
int get_hp() const {
|
||||
return hp;
|
||||
}
|
||||
|
||||
void set_hp( int value ) {
|
||||
hp = value;
|
||||
}
|
||||
|
||||
int get_max_hp() const {
|
||||
return hp;
|
||||
}
|
||||
|
||||
void set_max_hp( int value ) {
|
||||
maxhp = value;
|
||||
}
|
||||
|
||||
private:
|
||||
int hp = 50;
|
||||
int maxhp = 50;
|
||||
};
|
||||
|
||||
int main (int, char*[]) {
|
||||
|
||||
std::cout << "=== properties from C++ functions ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set("theplayer", Player());
|
||||
|
||||
// Yes, you can register after you set a value and it will
|
||||
// connect up the usertype automatically
|
||||
lua.new_usertype<Player>( "Player",
|
||||
"hp", sol::property(&Player::get_hp, &Player::set_hp),
|
||||
"maxHp", sol::property(&Player::get_max_hp, &Player::set_max_hp)
|
||||
);
|
||||
|
||||
const auto& code = R"(
|
||||
-- variable syntax, calls functions
|
||||
theplayer.hp = 20
|
||||
print('hp:', theplayer.hp)
|
||||
print('max hp:', theplayer.maxHp)
|
||||
)";
|
||||
|
||||
lua.script(code);
|
||||
|
||||
return 0;
|
||||
}
|
27
examples/protect.cpp
Normal file
27
examples/protect.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
int main () {
|
||||
struct protect_me {
|
||||
int gen(int x) {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_usertype<protect_me>("protect_me",
|
||||
"gen", sol::protect( &protect_me::gen )
|
||||
);
|
||||
|
||||
lua.script(R"__(
|
||||
pm = protect_me.new()
|
||||
value = pcall(pm.gen,"wrong argument")
|
||||
)__");
|
||||
bool value = lua["value"];
|
||||
c_assert(!value);
|
||||
|
||||
return 0;
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "=== protected_functions example ===" << std::endl;
|
||||
std::cout << "=== protected_functions ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
48
examples/read_only.cpp
Normal file
48
examples/read_only.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
struct object {
|
||||
void my_func() {
|
||||
std::cout << "hello\n";
|
||||
}
|
||||
};
|
||||
|
||||
int deny(lua_State* L) {
|
||||
return luaL_error(L, "HAH! Deniiiiied!");
|
||||
}
|
||||
|
||||
int main() {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
object my_obj;
|
||||
|
||||
sol::table obj_table = lua.create_named_table("object");
|
||||
|
||||
sol::table obj_metatable = lua.create_table_with();
|
||||
obj_metatable.set_function("my_func", &object::my_func, &my_obj);
|
||||
// Set whatever else you need to
|
||||
// on the obj_metatable,
|
||||
// not on the obj_table itself!
|
||||
|
||||
// Properly self-index metatable to block things
|
||||
obj_metatable[sol::meta_function::new_index] = deny;
|
||||
obj_metatable[sol::meta_function::index] = obj_metatable;
|
||||
|
||||
// Set it on the actual table
|
||||
obj_table[sol::metatable_key] = obj_metatable;
|
||||
|
||||
try {
|
||||
lua.script(R"(
|
||||
print(object.my_func)
|
||||
object["my_func"] = 24
|
||||
print(object.my_func)
|
||||
)");
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cout << "an expected error occurred: " << e.what() << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -25,7 +25,7 @@ sol::table open_mylib(sol::this_state s) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "=== require example ===" << std::endl;
|
||||
std::cout << "=== require ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::package, sol::lib::base);
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== require from DLL example ===" << std::endl;
|
||||
std::cout << "=== require from DLL ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::package, sol::lib::base);
|
||||
|
@ -9,7 +9,7 @@ struct object {
|
||||
};
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== runtime_additions example ===" << std::endl;
|
||||
std::cout << "=== runtime_additions ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int, char**) {
|
||||
std::cout << "=== script error handling example ===" << std::endl;
|
||||
std::cout << "=== script error handling ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
|
||||
|
@ -40,7 +40,7 @@ std::shared_ptr<SomeLib> SomeLib::getInstance() {
|
||||
}
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== singleton example ===" << std::endl;
|
||||
std::cout << "=== singleton ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -11,7 +11,7 @@ int test::muh_variable = 25;
|
||||
|
||||
|
||||
int main() {
|
||||
std::cout << "=== static_variables example ===" << std::endl;
|
||||
std::cout << "=== static_variables ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
@ -7,7 +7,7 @@
|
||||
// this example shows how to read data in from a lua table
|
||||
|
||||
int main() {
|
||||
std::cout << "=== tables example ===" << std::endl;
|
||||
std::cout << "=== tables ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
// table used as an array
|
||||
|
39
examples/tie.cpp
Normal file
39
examples/tie.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
int main (int, char*[]) {
|
||||
|
||||
const auto& code = R"(
|
||||
bark_power = 11;
|
||||
|
||||
function woof ( bark_energy )
|
||||
return (bark_energy * (bark_power / 4))
|
||||
end
|
||||
)";
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.script(code);
|
||||
|
||||
sol::function woof = lua["woof"];
|
||||
double numwoof = woof(20);
|
||||
c_assert(numwoof == 55.0);
|
||||
|
||||
lua.script( "function f () return 10, 11, 12 end" );
|
||||
|
||||
sol::function f = lua["f"];
|
||||
std::tuple<int, int, int> abc = f();
|
||||
c_assert(std::get<0>(abc) == 10);
|
||||
c_assert(std::get<1>(abc) == 11);
|
||||
c_assert(std::get<2>(abc) == 12);
|
||||
// or
|
||||
int a, b, c;
|
||||
sol::tie(a, b, c) = f();
|
||||
c_assert(a == 10);
|
||||
c_assert(b == 11);
|
||||
c_assert(c == 12);
|
||||
|
||||
return 0;
|
||||
}
|
@ -21,7 +21,7 @@ struct some_class {
|
||||
};
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== functions (all) example ===" << std::endl;
|
||||
std::cout << "=== functions (all) ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "../../assert.hpp"
|
||||
|
||||
int main() {
|
||||
std::cout << "=== namespacing example ===" << std::endl;
|
||||
std::cout << "=== namespacing ===" << std::endl;
|
||||
|
||||
struct my_class {
|
||||
int b = 24;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "../../assert.hpp"
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== opening a state example ===" << std::endl;
|
||||
std::cout << "=== opening a state ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
// open some common libraries
|
||||
|
@ -10,7 +10,7 @@ int use_sol2(lua_State* L) {
|
||||
}
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== opening sol::state_view on raw Lua example ===" << std::endl;
|
||||
std::cout << "=== opening sol::state_view on raw Lua ===" << std::endl;
|
||||
|
||||
lua_State* L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "../../assert.hpp"
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== running lua code example ===" << std::endl;
|
||||
std::cout << "=== running lua code ===" << std::endl;
|
||||
|
||||
{
|
||||
std::ofstream out("a_lua_script.lua");
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "../../assert.hpp"
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== running lua code (low level) example ===" << std::endl;
|
||||
std::cout << "=== running lua code (low level) ===" << std::endl;
|
||||
|
||||
{
|
||||
std::ofstream out("a_lua_script.lua");
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "=== self_call example ===" << std::endl;
|
||||
std::cout << "=== self_call ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::table);
|
||||
|
@ -20,7 +20,7 @@ struct Doge {
|
||||
};
|
||||
|
||||
int main(int, char* []) {
|
||||
std::cout << "=== userdata example ===" << std::endl;
|
||||
std::cout << "=== userdata ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
|
||||
|
@ -20,7 +20,7 @@ struct Doge {
|
||||
};
|
||||
|
||||
int main(int, char* []) {
|
||||
std::cout << "=== userdata memory reference example ===" << std::endl;
|
||||
std::cout << "=== userdata memory reference ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -19,7 +19,7 @@ struct Doge {
|
||||
};
|
||||
|
||||
int main(int, char* []) {
|
||||
std::cout << "=== usertypes example ===" << std::endl;
|
||||
std::cout << "=== usertypes ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -41,7 +41,7 @@ struct variables {
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== usertype example ===" << std::endl;
|
||||
std::cout << "=== usertype ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::math);
|
||||
|
@ -47,7 +47,7 @@ private:
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== usertype_advanced example ===" << std::endl;
|
||||
std::cout << "=== usertype_advanced ===" << std::endl;
|
||||
sol::state lua;
|
||||
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -63,7 +63,7 @@ std::ostream& operator<<(std::ostream& os, const automatic& right) {
|
||||
}
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== usertype automatic operators example ===" << std::endl;
|
||||
std::cout << "=== usertype automatic operators ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -115,7 +115,7 @@ struct __attribute__((packed, aligned(1))) flags_t {
|
||||
} flags{0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== usertype_bitfields example ===" << std::endl;
|
||||
std::cout << "=== usertype_bitfields ===" << std::endl;
|
||||
#ifdef __MINGW32__
|
||||
std::cout << "MinGW Detected, packing structs is broken in MinGW and this test may fail" << std::endl;
|
||||
#endif
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== usertype call from C++ example ===" << std::endl;
|
||||
std::cout << "=== usertype call from C++ ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -97,7 +97,7 @@ struct vec {
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== usertype dynamic getter/setter example ===" << std::endl;
|
||||
std::cout << "=== usertype dynamic getter/setter ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== usertype_initializers example ===" << std::endl;
|
||||
std::cout << "=== usertype_initializers ===" << std::endl;
|
||||
{ // additional scope to make usertype destroy earlier
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
@ -25,7 +25,7 @@ struct my_data {
|
||||
};
|
||||
|
||||
int main() {
|
||||
std::cout << "=== usertype_simple example ===" << std::endl;
|
||||
std::cout << "=== usertype_simple ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "=== variables example ===" << std::endl;
|
||||
std::cout << "=== variables ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "=== variadic_args example ===" << std::endl;
|
||||
std::cout << "=== variadic_args ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== lua inheritance example ===" << std::endl;
|
||||
std::cout << "=== lua inheritance ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
46
sol/call.hpp
46
sol/call.hpp
@ -221,13 +221,9 @@ namespace sol {
|
||||
construct_match<T, TypeLists...>(constructor_match<T, checked, clean_stack>(obj), L, argcount, 1 + static_cast<int>(syntax));
|
||||
|
||||
userdataref.push();
|
||||
luaL_getmetatable(L, &meta[0]);
|
||||
if (type_of(L, -1) == type::lua_nil) {
|
||||
lua_pop(L, 1);
|
||||
return luaL_error(L, "sol: unable to get usertype metatable");
|
||||
}
|
||||
stack::stack_detail::undefined_metatable<T> umf(L, &meta[0]);
|
||||
umf();
|
||||
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -508,7 +504,7 @@ namespace sol {
|
||||
typedef constructor_list<Args...> F;
|
||||
|
||||
static int call(lua_State* L, F&) {
|
||||
const auto& metakey = usertype_traits<T>::metatable();
|
||||
const auto& meta = usertype_traits<T>::metatable();
|
||||
int argcount = lua_gettop(L);
|
||||
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot;
|
||||
argcount -= static_cast<int>(syntax);
|
||||
@ -519,13 +515,9 @@ namespace sol {
|
||||
construct_match<T, Args...>(constructor_match<T, false, clean_stack>(obj), L, argcount, boost + 1 + static_cast<int>(syntax));
|
||||
|
||||
userdataref.push();
|
||||
luaL_getmetatable(L, &metakey[0]);
|
||||
if (type_of(L, -1) == type::lua_nil) {
|
||||
lua_pop(L, 1);
|
||||
return luaL_error(L, "sol: unable to get usertype metatable");
|
||||
}
|
||||
stack::stack_detail::undefined_metatable<T> umf(L, &meta[0]);
|
||||
umf();
|
||||
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
@ -537,7 +529,7 @@ namespace sol {
|
||||
struct onmatch {
|
||||
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
||||
int operator()(types<Fx>, index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start, F& f) {
|
||||
const auto& metakey = usertype_traits<T>::metatable();
|
||||
const auto& meta = usertype_traits<T>::metatable();
|
||||
T* obj = detail::usertype_allocate<T>(L);
|
||||
reference userdataref(L, -1);
|
||||
|
||||
@ -545,14 +537,8 @@ namespace sol {
|
||||
stack::call_into_lua<checked, clean_stack>(r, a, L, boost + start, func, detail::implicit_wrapper<T>(obj));
|
||||
|
||||
userdataref.push();
|
||||
luaL_getmetatable(L, &metakey[0]);
|
||||
if (type_of(L, -1) == type::lua_nil) {
|
||||
lua_pop(L, 1);
|
||||
std::string err = "sol: unable to get usertype metatable for ";
|
||||
err += usertype_traits<T>::name();
|
||||
return luaL_error(L, err.c_str());
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
stack::stack_detail::undefined_metatable<T> umf(L, &meta[0]);
|
||||
umf();
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -579,11 +565,25 @@ namespace sol {
|
||||
struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, clean_stack, std::enable_if_t<!std::is_void<Fx>::value>> {
|
||||
typedef destructor_wrapper<Fx> F;
|
||||
|
||||
static int call(lua_State* L, const F& f) {
|
||||
static int call_void(std::true_type, lua_State* L, const F& f) {
|
||||
typedef meta::bind_traits<meta::unqualified_t<decltype(f.fx)>> bt;
|
||||
typedef typename bt::template arg_at<0> arg0;
|
||||
typedef meta::unqualified_t<arg0> O;
|
||||
|
||||
O& obj = stack::get<O>(L);
|
||||
f.fx(detail::implicit_wrapper<O>(obj));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int call_void(std::false_type, lua_State* L, const F& f) {
|
||||
T& obj = stack::get<T>(L);
|
||||
f.fx(detail::implicit_wrapper<T>(obj));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int call(lua_State* L, const F& f) {
|
||||
return call_void(std::is_void<T>(), L, f);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
|
||||
|
39
sol/experimental_usertype.hpp
Normal file
39
sol/experimental_usertype.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
// sol2
|
||||
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef SOL_EXPERIMENTAL_USERTYPE_HPP
|
||||
#define SOL_EXPERIMENTAL_USERTYPE_HPP
|
||||
|
||||
#include "table.hpp"
|
||||
|
||||
namespace sol {
|
||||
|
||||
template <typename T>
|
||||
struct metatable : basic_table<T> {
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif SOL_EXPERIMENTAL_USERTYPE_HPP
|
@ -431,6 +431,20 @@ namespace sol {
|
||||
lua_CFunction cf = call_detail::construct<T, detail::default_safe_function_calls, true, Lists...>;
|
||||
return stack::push(L, cf);
|
||||
}
|
||||
|
||||
static int push(lua_State* L, constructor_list<Lists...>) {
|
||||
lua_CFunction cf = call_detail::construct<T, detail::default_safe_function_calls, true, Lists...>;
|
||||
return stack::push(L, cf);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename L0, typename... Lists>
|
||||
struct pusher<constructor_list<L0, Lists...>> {
|
||||
typedef constructor_list<L0, Lists...> cl_t;
|
||||
static int push(lua_State* L, cl_t cl) {
|
||||
typedef typename meta::bind_traits<L0>::return_type T;
|
||||
return stack::push<detail::tagged<T, cl_t>>(L, cl);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename... Fxs>
|
||||
@ -445,6 +459,16 @@ namespace sol {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename... Fxs>
|
||||
struct pusher<constructor_wrapper<F, Fxs...>> {
|
||||
template <typename C>
|
||||
static int push(lua_State* L, C&& c) {
|
||||
typedef typename meta::bind_traits<F>::template arg_at<0> arg0;
|
||||
typedef meta::unqualified_t<std::remove_pointer_t<arg0>> T;
|
||||
return stack::push<detail::tagged<T, constructor_wrapper<F, Fxs...>>>(L, std::forward<C>(c));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct pusher<detail::tagged<T, destructor_wrapper<void>>> {
|
||||
static int push(lua_State* L, destructor_wrapper<void>) {
|
||||
@ -455,11 +479,38 @@ namespace sol {
|
||||
|
||||
template <typename T, typename Fx>
|
||||
struct pusher<detail::tagged<T, destructor_wrapper<Fx>>> {
|
||||
static int push(lua_State* L, destructor_wrapper<Fx> c) {
|
||||
static int push(lua_State* L, destructor_wrapper<Fx>&& c) {
|
||||
lua_CFunction cf = call_detail::call_user<T, false, false, destructor_wrapper<Fx>, 2>;
|
||||
int upvalues = 0;
|
||||
upvalues += stack::push(L, nullptr);
|
||||
upvalues += stack::push<user<T>>(L, std::move(c));
|
||||
upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, std::move(c));
|
||||
return stack::push(L, c_closure(cf, upvalues));
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const destructor_wrapper<Fx>& c) {
|
||||
lua_CFunction cf = call_detail::call_user<T, false, false, destructor_wrapper<Fx>, 2>;
|
||||
int upvalues = 0;
|
||||
upvalues += stack::push(L, nullptr);
|
||||
upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, c);
|
||||
return stack::push(L, c_closure(cf, upvalues));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Fx>
|
||||
struct pusher<destructor_wrapper<Fx>> {
|
||||
static int push(lua_State* L, destructor_wrapper<Fx>&& c) {
|
||||
lua_CFunction cf = call_detail::call_user<void, false, false, destructor_wrapper<Fx>, 2>;
|
||||
int upvalues = 0;
|
||||
upvalues += stack::push(L, nullptr);
|
||||
upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, std::move(c));
|
||||
return stack::push(L, c_closure(cf, upvalues));
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const destructor_wrapper<Fx>& c) {
|
||||
lua_CFunction cf = call_detail::call_user<void, false, false, destructor_wrapper<Fx>, 2>;
|
||||
int upvalues = 0;
|
||||
upvalues += stack::push(L, nullptr);
|
||||
upvalues += stack::push<user<destructor_wrapper<Fx>>>(L, c);
|
||||
return stack::push(L, c_closure(cf, upvalues));
|
||||
}
|
||||
};
|
||||
|
@ -122,13 +122,7 @@ namespace sol {
|
||||
|
||||
template <typename... Ret, typename... Args>
|
||||
decltype(auto) call(Args&&... args) {
|
||||
#if defined(_MSC_VER) && _MSC_VER == 1913
|
||||
// This compiler is bananas
|
||||
// B, A N A N A S
|
||||
return get<protected_function>().call<Ret...>(std::forward<Args>(args)...);
|
||||
#else
|
||||
return get<protected_function>().template call<Ret...>(std::forward<Args>(args)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
|
@ -25,7 +25,6 @@
|
||||
#define SOL_USERTYPE_CORE_HPP
|
||||
|
||||
#include "wrapper.hpp"
|
||||
#include "call.hpp"
|
||||
#include "stack.hpp"
|
||||
#include "types.hpp"
|
||||
#include "stack_reference.hpp"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user