mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
protect could use some additional optimizations for space, but I'm kinna tired.
This commit is contained in:
parent
14ced4af69
commit
febfdbadb7
|
@ -21,6 +21,8 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo
|
||||||
stack_reference
|
stack_reference
|
||||||
make_reference
|
make_reference
|
||||||
overload
|
overload
|
||||||
|
protect
|
||||||
|
readonly
|
||||||
property
|
property
|
||||||
proxy
|
proxy
|
||||||
resolve
|
resolve
|
||||||
|
|
33
docs/source/api/protect.rst
Normal file
33
docs/source/api/protect.rst
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
protect
|
||||||
|
=======
|
||||||
|
Routine to mark a function / variable as requiring safety
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto protect( T&& value );
|
||||||
|
|
||||||
|
``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 turn 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
|
11
docs/source/api/readonly.rst
Normal file
11
docs/source/api/readonly.rst
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
readonly
|
||||||
|
========
|
||||||
|
Routine to mark a member variable as read-only
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto readonly( T&& value );
|
||||||
|
|
||||||
|
The goal of read-only is to protect a variable set on a usertype or set as a function into Lua. Simply wrap it around a ``&my_class::my_member_variable`` in the appropriate place to use it.
|
|
@ -3,6 +3,8 @@ safety
|
||||||
|
|
||||||
Sol was designed to be correct and fast, and in the pursuit of both uses the regular ``lua_to{x}`` functions of Lua rather than the checking versions (``lua_check{X}``) functions. The API defaults to paranoidly-safe alternatives if you have a ``#define SOL_CHECK_ARGUMENTS`` before you include Sol, or if you pass the ``SOL_CHECK_ARGUMENTS`` define on the build command for your build system. By default, it is off and remains off unless you define this, even in debug mode. The same goes for ``#define SOL_SAFE_USERTYPE``.
|
Sol was designed to be correct and fast, and in the pursuit of both uses the regular ``lua_to{x}`` functions of Lua rather than the checking versions (``lua_check{X}``) functions. The API defaults to paranoidly-safe alternatives if you have a ``#define SOL_CHECK_ARGUMENTS`` before you include Sol, or if you pass the ``SOL_CHECK_ARGUMENTS`` define on the build command for your build system. By default, it is off and remains off unless you define this, even in debug mode. The same goes for ``#define SOL_SAFE_USERTYPE``.
|
||||||
|
|
||||||
|
Note that you can obtain safety with regards to functions you bind by using the :doc:`protect<api/protect>` wrapper around function/variable bindings you set into Lua.
|
||||||
|
|
||||||
``SOL_SAFE_USERTYPE`` triggers the following change:
|
``SOL_SAFE_USERTYPE`` triggers the following change:
|
||||||
* If the userdata to a usertype function is nill, will trigger an error instead of letting things go through and letting the system segfault
|
* If the userdata to a usertype function is nill, will trigger an error instead of letting things go through and letting the system segfault
|
||||||
|
|
||||||
|
@ -13,7 +15,6 @@ Sol was designed to be correct and fast, and in the pursuit of both uses the reg
|
||||||
|
|
||||||
Remember that if you want these features, you must explicitly turn them on. Additionally, you can have basic boolean checks when using the API by just converting to a :doc:`sol::optional\<T><api/optional>` when necessary. Tests are compiled with this on to ensure everythign is going as expected.
|
Remember that if you want these features, you must explicitly turn them on. Additionally, you can have basic boolean checks when using the API by just converting to a :doc:`sol::optional\<T><api/optional>` when necessary. Tests are compiled with this on to ensure everythign is going as expected.
|
||||||
|
|
||||||
|
|
||||||
Finally, some warnings that may help with errors when working with Sol:
|
Finally, some warnings that may help with errors when working with Sol:
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
|
@ -151,7 +151,7 @@ You can erase things by setting it to ``nullptr`` or ``sol::nil``.
|
||||||
// second_try == 322
|
// second_try == 322
|
||||||
|
|
||||||
|
|
||||||
Note that if its a :doc:`userdata/usertype<../doc/usertype>` for a C++ type, the destructor will run only when the garbage collector deems it appropriate to destroy the memory. If you are relying on the destructor being run when its set to ``sol::nil``, you're probably committing a mistake.
|
Note that if its a :doc:`userdata/usertype<../api/usertype>` for a C++ type, the destructor will run only when the garbage collector deems it appropriate to destroy the memory. If you are relying on the destructor being run when its set to ``sol::nil``, you're probably committing a mistake.
|
||||||
|
|
||||||
tables
|
tables
|
||||||
------
|
------
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace sol {
|
||||||
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
||||||
int call(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int) {
|
int call(types<Fx>, index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int) {
|
||||||
auto& func = std::get<I>(overloads);
|
auto& func = std::get<I>(overloads);
|
||||||
return call_detail::call_wrapped<void, false, false>(L, func);
|
return call_detail::call_wrapped<void, true, false>(L, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
int operator()(lua_State* L) {
|
int operator()(lua_State* L) {
|
||||||
|
|
|
@ -33,15 +33,16 @@ namespace sol {
|
||||||
|
|
||||||
static int real_call(lua_State* L) {
|
static int real_call(lua_State* L) {
|
||||||
auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L);
|
auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L);
|
||||||
function_type* f = udata.first;
|
function_type* fx = udata.first;
|
||||||
return call_detail::call_wrapped<void, false, false>(L, f);
|
int r = stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int call(lua_State* L) {
|
static int call(lua_State* L) {
|
||||||
return detail::static_trampoline<(&real_call)>(L);
|
return detail::static_trampoline<(&real_call)>(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
int operator()(lua_State* L) const {
|
int operator()(lua_State* L) {
|
||||||
return call(L);
|
return call(L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -61,7 +62,10 @@ namespace sol {
|
||||||
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
|
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
|
||||||
function_type& memfx = memberdata.first;
|
function_type& memfx = memberdata.first;
|
||||||
auto& item = *objdata.first;
|
auto& item = *objdata.first;
|
||||||
return call_detail::call_wrapped<T, false, false, -1>(L, memfx, item);
|
auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type {
|
||||||
|
return (item.*memfx)(std::forward<decltype(args)>(args)...);
|
||||||
|
};
|
||||||
|
return stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int call(lua_State* L) {
|
static int call(lua_State* L) {
|
||||||
|
@ -73,6 +77,30 @@ namespace sol {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <int N, typename R, typename M, typename V>
|
||||||
|
int set_assignable(std::false_type, lua_State* L, M&, V&) {
|
||||||
|
lua_pop(L, N);
|
||||||
|
return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N, typename R, typename M, typename V>
|
||||||
|
int set_assignable(std::true_type, lua_State* L, M& mem, V& var) {
|
||||||
|
(mem.*var) = stack::get<R>(L, N);
|
||||||
|
lua_pop(L, N);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N, typename R, typename M, typename V>
|
||||||
|
int set_variable(std::true_type, lua_State* L, M& mem, V& var) {
|
||||||
|
return set_assignable<N, R>(std::is_assignable<std::add_lvalue_reference_t<R>, R>(), L, mem, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N, typename R, typename M, typename V>
|
||||||
|
int set_variable(std::false_type, lua_State* L, M&, V&) {
|
||||||
|
lua_pop(L, N);
|
||||||
|
return luaL_error(L, "sol: cannot write to a const variable");
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T, typename Function>
|
template<typename T, typename Function>
|
||||||
struct upvalue_member_variable {
|
struct upvalue_member_variable {
|
||||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||||
|
@ -90,9 +118,11 @@ namespace sol {
|
||||||
function_type& var = memberdata.first;
|
function_type& var = memberdata.first;
|
||||||
switch (lua_gettop(L)) {
|
switch (lua_gettop(L)) {
|
||||||
case 0:
|
case 0:
|
||||||
return call_detail::call_wrapped<T, true, false, -1>(L, var, mem);
|
stack::push(L, (mem.*var));
|
||||||
|
return 1;
|
||||||
case 1:
|
case 1:
|
||||||
return call_detail::call_wrapped<T, false, false, -1>(L, var, mem);
|
set_variable<1, typename traits_type::return_type>(meta::neg<std::is_const<typename traits_type::return_type>>(), L, mem, var);
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
||||||
}
|
}
|
||||||
|
@ -138,12 +168,16 @@ namespace sol {
|
||||||
// Layout:
|
// Layout:
|
||||||
// idx 1...n: verbatim data of member variable pointer
|
// idx 1...n: verbatim data of member variable pointer
|
||||||
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
||||||
|
auto& mem = stack::get<T>(L, 1);
|
||||||
function_type& var = memberdata.first;
|
function_type& var = memberdata.first;
|
||||||
switch (lua_gettop(L)) {
|
switch (lua_gettop(L)) {
|
||||||
case 1:
|
case 1:
|
||||||
return call_detail::call_wrapped<T, true, false>(L, var);
|
lua_pop(L, 1);
|
||||||
|
stack::push(L, (mem.*var));
|
||||||
|
return 1;
|
||||||
case 2:
|
case 2:
|
||||||
return call_detail::call_wrapped<T, false, false>(L, var);
|
set_variable<2, typename traits_type::return_type>(meta::neg<std::is_const<typename traits_type::return_type>>(), L, mem, var);
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
||||||
}
|
}
|
||||||
|
|
|
@ -528,20 +528,28 @@ I = i(o1)
|
||||||
J0 = j()
|
J0 = j()
|
||||||
j(24)
|
j(24)
|
||||||
J1 = j()
|
J1 = j()
|
||||||
|
)");
|
||||||
|
|
||||||
|
lua.script(R"(
|
||||||
K0 = k(o2)
|
K0 = k(o2)
|
||||||
k(o2, 1024)
|
k(o2, 1024)
|
||||||
K1 = k(o2)
|
K1 = k(o2)
|
||||||
|
)");
|
||||||
|
|
||||||
|
lua.script(R"(
|
||||||
L0 = l(o1)
|
L0 = l(o1)
|
||||||
l(o1, 678)
|
l(o1, 678)
|
||||||
L1 = l(o1)
|
L1 = l(o1)
|
||||||
|
)");
|
||||||
|
|
||||||
|
|
||||||
|
lua.script(R"(
|
||||||
M0 = m()
|
M0 = m()
|
||||||
m(256)
|
m(256)
|
||||||
M1 = m()
|
M1 = m()
|
||||||
|
)");
|
||||||
|
|
||||||
|
lua.script(R"(
|
||||||
N = n(1, 2, 3)
|
N = n(1, 2, 3)
|
||||||
)");
|
)");
|
||||||
int ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1, N;
|
int ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1, N;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user