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
|
||||
make_reference
|
||||
overload
|
||||
protect
|
||||
readonly
|
||||
property
|
||||
proxy
|
||||
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``.
|
||||
|
||||
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:
|
||||
* 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.
|
||||
|
||||
|
||||
Finally, some warnings that may help with errors when working with Sol:
|
||||
|
||||
.. warning::
|
||||
|
|
|
@ -151,7 +151,7 @@ You can erase things by setting it to ``nullptr`` or ``sol::nil``.
|
|||
// 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
|
||||
------
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace sol {
|
|||
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) {
|
||||
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) {
|
||||
|
|
|
@ -33,15 +33,16 @@ namespace sol {
|
|||
|
||||
static int real_call(lua_State* L) {
|
||||
auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L);
|
||||
function_type* f = udata.first;
|
||||
return call_detail::call_wrapped<void, false, false>(L, f);
|
||||
function_type* fx = udata.first;
|
||||
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) {
|
||||
return detail::static_trampoline<(&real_call)>(L);
|
||||
}
|
||||
|
||||
int operator()(lua_State* L) const {
|
||||
int operator()(lua_State* L) {
|
||||
return call(L);
|
||||
}
|
||||
};
|
||||
|
@ -61,7 +62,10 @@ namespace sol {
|
|||
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
|
||||
function_type& memfx = memberdata.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) {
|
||||
|
@ -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>
|
||||
struct upvalue_member_variable {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
|
@ -90,9 +118,11 @@ namespace sol {
|
|||
function_type& var = memberdata.first;
|
||||
switch (lua_gettop(L)) {
|
||||
case 0:
|
||||
return call_detail::call_wrapped<T, true, false, -1>(L, var, mem);
|
||||
stack::push(L, (mem.*var));
|
||||
return 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:
|
||||
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
||||
}
|
||||
|
@ -138,12 +168,16 @@ namespace sol {
|
|||
// Layout:
|
||||
// idx 1...n: verbatim data of member variable pointer
|
||||
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
||||
auto& mem = stack::get<T>(L, 1);
|
||||
function_type& var = memberdata.first;
|
||||
switch (lua_gettop(L)) {
|
||||
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:
|
||||
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:
|
||||
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
||||
}
|
||||
|
|
|
@ -528,20 +528,28 @@ I = i(o1)
|
|||
J0 = j()
|
||||
j(24)
|
||||
J1 = j()
|
||||
)");
|
||||
|
||||
lua.script(R"(
|
||||
K0 = k(o2)
|
||||
k(o2, 1024)
|
||||
K1 = k(o2)
|
||||
)");
|
||||
|
||||
lua.script(R"(
|
||||
L0 = l(o1)
|
||||
l(o1, 678)
|
||||
L1 = l(o1)
|
||||
)");
|
||||
|
||||
|
||||
lua.script(R"(
|
||||
M0 = m()
|
||||
m(256)
|
||||
M1 = m()
|
||||
)");
|
||||
|
||||
lua.script(R"(
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user