protect could use some additional optimizations for space, but I'm kinna tired.

This commit is contained in:
ThePhD 2016-07-09 03:43:51 -04:00
parent 14ced4af69
commit febfdbadb7
8 changed files with 100 additions and 11 deletions

View File

@ -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

View 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

View 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.

View File

@ -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::

View File

@ -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
------ ------

View File

@ -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) {

View File

@ -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");
} }

View File

@ -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;