this_environment is now live

This commit is contained in:
ThePhD 2017-05-09 13:24:56 -04:00
parent c7237806ef
commit 58003669fb
15 changed files with 239 additions and 47 deletions

View File

@ -10,12 +10,14 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo
:maxdepth: 2 :maxdepth: 2
state state
this_state
reference reference
stack_reference stack_reference
make_reference make_reference
table table
userdata userdata
environment environment
this_environment
proxy proxy
containers containers
nested nested
@ -32,7 +34,6 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo
object object
thread thread
optional optional
this_state
variadic_args variadic_args
as_args as_args
overload overload

View File

@ -175,7 +175,7 @@ This is an SFINAE-friendly struct that is meant to expose static function ``get`
} }
}; };
This is an SFINAE-friendly struct that is meant to expose static function ``push`` that returns the number of things pushed onto the stack. The default implementation assumes ``T`` is a usertype and pushes a userdata into Lua with a :ref:`usertype_traits\<T><usertype-traits>` metatable associated with it. There are implementations for pushing numbers (``std::is_floating``, ``std::is_integral``-matching types), getting ``std::string`` and ``const char*``, getting raw userdata with :doc:`userdata<types>` and raw upvalues with :doc:`upvalue<types>`, getting raw `lua_CFunction`_ s, and finally pulling out Lua functions into ``sol::function``. It is also defined for anything that derives from :doc:`sol::reference<reference>`. It also has a special implementation for the 2 standard library smart pointers (see :doc:`usertype memory<usertype_memory>`). This is an SFINAE-friendly struct that is meant to expose static function ``push`` that returns the number of things pushed onto the stack. The default implementation assumes ``T`` is a usertype and pushes a userdata into Lua with a class-specific, state-wide metatable associated with it. There are implementations for pushing numbers (``std::is_floating``, ``std::is_integral``-matching types), getting ``std::string`` and ``const char*``, getting raw userdata with :doc:`userdata<types>` and raw upvalues with :doc:`upvalue<types>`, getting raw `lua_CFunction`_ s, and finally pulling out Lua functions into ``sol::function``. It is also defined for anything that derives from :doc:`sol::reference<reference>`. It also has a special implementation for the 2 standard library smart pointers (see :doc:`usertype memory<usertype_memory>`).
.. code-block:: cpp .. code-block:: cpp
:caption: struct: checker :caption: struct: checker

View File

@ -93,7 +93,7 @@ To handle errors when using the second overload, provide a callable function/obj
}); });
} }
You can also pass a :doc:`sol::environment<environment>` to ``script``/``script_file`` to have the script have sandboxed / contained in a way inside of a state. This is useful for runnig multiple different "perspectives" or "views" on the same state. See the ``sol: You can also pass a :doc:`sol::environment<environment>` to ``script``/``script_file`` to have the script have sandboxed / contained in a way inside of a state. This is useful for runnig multiple different "perspectives" or "views" on the same state, and even has fallback support. See the :doc:`sol::environment<environment>` documentation for more details.
.. code-block:: cpp .. code-block:: cpp
:caption: function: require / require_file :caption: function: require / require_file

View File

@ -0,0 +1,44 @@
this_environment
================
retrieving the environment of the calling function
--------------------------------------------------
Sometimes in C++ it's useful to know where a Lua call is coming from and what :doc:`environment<environment>` it is from. The former is covered by Lua's Debug API, which is extensive and is not fully wrapped up by sol2. But, sol2 covers the latter in letting you get the environment of the calling script / function, if it has one. ``sol::this_environment`` is a *transparent argument* and does not need to be passed in Lua scripts or provided when using :doc:`sol::function<function>`, similar to :doc:`sol::this_state<this_state>`:
.. code-block:: cpp
:linenos:
#define SOL_CHECK_ARGUMENTS
#include <sol.hpp>
#include <iostream>
void env_check(sol::this_state ts, int x, sol::this_environment te) {
std::cout << "In C++, 'int x' is in the second position, and its value is: " << x << std::endl;
if (!te) {
std::cout << "function does not have an environment: exiting function early" << std::endl;
return;
}
sol::environment& env = te;
sol::state_view lua = ts;
sol::environment freshenv = lua["freshenv"];
bool is_same_env = freshenv == env;
std::cout << "env == freshenv : " << is_same_env << std::endl;
}
int main() {
sol::state lua;
sol::environment freshenv(lua, sol::create, lua.globals());
lua["freshenv"] = freshenv;
lua.set_function("f", env_check);
lua.script("f(25)", freshenv);
return 0;
}
Also see `this example`_ for more details.
.. _this example: https://github.com/ThePhD/sol2/blob/develop/examples/environment_snooping.cpp

View File

@ -5,14 +5,14 @@ usertype memory
Sol does not take ownership of raw pointers, returned from functions or set through the ``set`` functions. Return a value, a ``std::unique_ptr``, a ``std::shared_ptr`` of some kind, or hook up the :doc:`unique usertypes traits<unique_usertype_traits>` to work for some specific handle structure you use (AKA, for ``boost::shared_ptr``). Sol does not take ownership of raw pointers, returned from functions or set through the ``set`` functions. Return a value, a ``std::unique_ptr``, a ``std::shared_ptr`` of some kind, or hook up the :doc:`unique usertypes traits<unique_usertype_traits>` to work for some specific handle structure you use (AKA, for ``boost::shared_ptr``).
The userdata generated by Sol has a specific layout, depending on how Sol recognizes userdata passed into it. All of the referred to metatable names are generated from :ref:`usertype_traits\<T><usertype-traits>`. Note that we use 1 metatable per the 3 styles listed below, plus 1 additional metatable that is used for the actual table that you bind with the name when calling ``table::new/set_(simple_)usertype``. The userdata generated by Sol has a specific layout, depending on how Sol recognizes userdata passed into it. All of the referred to metatable names are generated from the name of the class itself. Note that we use 1 metatable per the 3 styles listed below, plus 1 additional metatable that is used for the actual table that you bind with the name when calling ``table::new/set_(simple_)usertype``.
In general, we always insert a T* in the first `sizeof(T*)` bytes, so the any framework that pulls out those first bytes expecting a pointer will work. The rest of the data has some different alignments and contents based on what it's used for and how it's used. In general, we always insert a T* in the first `sizeof(T*)` bytes, so the any framework that pulls out those first bytes expecting a pointer will work. The rest of the data has some different alignments and contents based on what it's used for and how it's used.
For ``T`` For ``T``
--------- ---------
These are classified with the metatable name from :ref:`usertype_traits\<T><usertype-traits>`. These are classified with a metatable name generally derived from the class name itself.
The data layout for references is as follows:: The data layout for references is as follows::

View File

@ -4,13 +4,24 @@
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
// Simple sol2 version of the below
void simple(sol::this_state ts, sol::this_environment te) {
sol::state_view lua = ts;
if (te) {
sol::environment& env = te;
sol::environment freshenv = lua["freshenv"];
bool is_same_env = freshenv == env;
std::cout << "this_environment -- env == freshenv : " << is_same_env << std::endl;
}
std::cout << "this_environment -- no environment present" << std::endl;
}
// NOTE: // NOTE:
// THIS IS A LOW-LEVEL EXAMPLE, using pieces of sol2 // THIS IS A LOW-LEVEL EXAMPLE, using pieces of sol2
// to facilitate better usage // to facilitate better usage
// If you need to do this often, you can copy this code and paste it in a utility function for yourself // It is recommended you just do the simple version, as it is basically this code
// so you can grab the environment whenever you need to // but it is sometimes useful to show the hoops you need to jump through to use the Lua C API
void complicated(sol::this_state ts) {
void some_function_called_by_sol2(sol::this_state ts) {
lua_State* L = ts; lua_State* L = ts;
lua_Debug info; lua_Debug info;
@ -30,14 +41,14 @@ void some_function_called_by_sol2(sol::this_state ts) {
// the rest is for printing / debugging purposes // the rest is for printing / debugging purposes
if (lua_getinfo(L, "fnluS", &info) == 0) { if (lua_getinfo(L, "fnluS", &info) == 0) {
// failure? // failure?
std::cout << "error: unable to get stack information" << std::endl; std::cout << "manually -- error: unable to get stack information" << std::endl;
lua_settop(L, pre_stack_size); lua_settop(L, pre_stack_size);
return; return;
} }
// Okay, so all the calls worked. // Okay, so all the calls worked.
// Print out some information about this "level" // Print out some information about this "level"
std::cout << "[" << level << "] " << info.short_src << ":" << info.currentline std::cout << "manually -- [" << level << "] " << info.short_src << ":" << info.currentline
<< " -- " << (info.name ? info.name : "<unknown>") << "[" << info.what << "]" << std::endl; << " -- " << (info.name ? info.name : "<unknown>") << "[" << info.what << "]" << std::endl;
// Grab the function off the top of the stack // Grab the function off the top of the stack
@ -48,14 +59,14 @@ void some_function_called_by_sol2(sol::this_state ts) {
// The environment can now be ripped out of the function // The environment can now be ripped out of the function
sol::environment env(sol::env_key, f); sol::environment env(sol::env_key, f);
if (!env.valid()) { if (!env.valid()) {
std::cout << "error: no environment to get" << std::endl; std::cout << "manually -- error: no environment to get" << std::endl;
lua_settop(L, pre_stack_size); lua_settop(L, pre_stack_size);
return; return;
} }
sol::state_view lua(L); sol::state_view lua(L);
sol::environment freshenv = lua["freshenv"]; sol::environment freshenv = lua["freshenv"];
bool is_same_env = freshenv == env; bool is_same_env = freshenv == env;
std::cout << "env == freshenv : " << is_same_env << std::endl; std::cout << "manually -- env == freshenv : " << is_same_env << std::endl;
} }
int main() { int main() {
@ -64,9 +75,11 @@ int main() {
sol::environment freshenv(lua, sol::create, lua.globals()); sol::environment freshenv(lua, sol::create, lua.globals());
lua["freshenv"] = freshenv; lua["freshenv"] = freshenv;
lua.set_function("f", some_function_called_by_sol2); lua.set_function("f", simple);
lua.set_function("g", complicated);
lua.script("f()", freshenv); lua.script("f()", freshenv);
lua.script("g()", freshenv);
return 0; return 0;
} }

View File

@ -597,9 +597,9 @@ namespace sol {
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...); return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <typename T, bool is_index, bool is_variable, typename F> template <typename T, bool is_index, bool is_variable, typename F, int start = 1>
inline int call_user(lua_State* L) { inline int call_user(lua_State* L) {
auto& fx = stack::get<user<F>>(L, upvalue_index(1)); auto& fx = stack::get<user<F>>(L, upvalue_index(start));
return call_wrapped<T, is_index, is_variable>(L, fx); return call_wrapped<T, is_index, is_variable>(L, fx);
} }

View File

@ -92,7 +92,8 @@ namespace sol {
#else #else
// Use upvalues as explained in Lua 5.2 and beyond's manual // Use upvalues as explained in Lua 5.2 and beyond's manual
this->push(); this->push();
if (lua_setupvalue(L, -2, 1) == nullptr) { const char* name = lua_setupvalue(L, -2, 1);
if (name == nullptr) {
this->pop(); this->pop();
} }
#endif #endif
@ -111,13 +112,74 @@ namespace sol {
return basic_environment<E>(L, -1); return basic_environment<E>(L, -1);
} }
struct this_environment {
optional<environment> env;
this_environment() : env(nullopt) {}
this_environment(sol::environment e) : env(std::move(e)) {}
this_environment(const this_environment&) = default;
this_environment(this_environment&&) = default;
this_environment& operator=(const this_environment&) = default;
this_environment& operator=(this_environment&&) = default;
explicit operator bool() const {
return static_cast<bool>(env);
}
operator optional<environment>& () {
return env;
}
operator const optional<environment>& () const {
return env;
}
operator environment& () {
return env.value();
}
operator const environment& () const {
return env.value();
}
};
namespace stack { namespace stack {
template <> template <>
struct getter<env_t> { struct getter<env_t> {
static environment get(lua_State* L, int index = -1) { static environment get(lua_State* L, int index, record& tracking) {
tracking.use(1);
return get_environment(stack_reference(L, raw_index(index))); return get_environment(stack_reference(L, raw_index(index)));
} }
}; };
template <>
struct getter<this_environment> {
static this_environment get(lua_State* L, int index, record& tracking) {
tracking.use(0);
lua_Debug info;
// Level 0 means current function (this C function, which may or may not be useful for us?)
// Level 1 means next call frame up the stack. (Can be nothing if function called directly from C++ with lua_p/call)
int pre_stack_size = lua_gettop(L);
if (lua_getstack(L, 1, &info) != 1) {
if (lua_getstack(L, 0, &info) != 1) {
lua_settop(L, pre_stack_size);
return this_environment();
}
}
if (lua_getinfo(L, "f", &info) == 0) {
lua_settop(L, pre_stack_size);
return this_environment();
}
sol::stack_reference f(L, -1);
sol::environment env(sol::env_key, f);
if (!env.valid()) {
lua_settop(L, pre_stack_size);
return this_environment();
}
return this_environment(std::move(env));
}
};
} // stack } // stack
} // sol } // sol

View File

@ -82,7 +82,9 @@ namespace sol {
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...); auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call; lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr);
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr))); upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
@ -101,7 +103,9 @@ namespace sol {
template <typename Fx, typename C> template <typename Fx, typename C>
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) { static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, fx); int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
@ -109,7 +113,9 @@ namespace sol {
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) { static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) {
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C; typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, fx); int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
@ -127,7 +133,9 @@ namespace sol {
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...); auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call; lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr);
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr))); upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
@ -146,7 +154,9 @@ namespace sol {
template <typename Fx, typename C> template <typename Fx, typename C>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) { static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, fx); int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
@ -154,7 +164,9 @@ namespace sol {
static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { static void select_member_function(std::true_type, lua_State* L, Fx&& fx) {
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C; typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, fx); int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
@ -168,7 +180,9 @@ namespace sol {
std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...); std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::call; lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, target); int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, target);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
@ -183,10 +197,12 @@ namespace sol {
template <typename Fx, typename... Args> template <typename Fx, typename... Args>
static void set_fx(lua_State* L, Args&&... args) { static void set_fx(lua_State* L, Args&&... args) {
lua_CFunction freefunc = function_detail::call<meta::unqualified_t<Fx>>; lua_CFunction freefunc = function_detail::call<meta::unqualified_t<Fx>, 2>;
stack::push<user<Fx>>(L, std::forward<Args>(args)...); int upvalues = 0;
stack::push(L, c_closure(freefunc, 1)); upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<Fx>>(L, std::forward<Args>(args)...);
stack::push(L, c_closure(freefunc, upvalues));
} }
template<typename... Args> template<typename... Args>
@ -254,15 +270,19 @@ namespace sol {
template <typename T> template <typename T>
struct pusher<protect_t<T>> { struct pusher<protect_t<T>> {
static int push(lua_State* L, protect_t<T>&& pw) { static int push(lua_State* L, protect_t<T>&& pw) {
lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>>; lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>, 2>;
int closures = stack::push<user<protect_t<T>>>(L, std::move(pw.value)); int upvalues = 0;
return stack::push(L, c_closure(cf, closures)); upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<protect_t<T>>>(L, std::move(pw.value));
return stack::push(L, c_closure(cf, upvalues));
} }
static int push(lua_State* L, const protect_t<T>& pw) { static int push(lua_State* L, const protect_t<T>& pw) {
lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>>; lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>, 2>;
int closures = stack::push<user<protect_t<T>>>(L, pw.value); int upvalues = 0;
return stack::push(L, c_closure(cf, closures)); upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<protect_t<T>>>(L, pw.value);
return stack::push(L, c_closure(cf, upvalues));
} }
}; };
@ -357,9 +377,11 @@ namespace sol {
struct pusher<detail::tagged<T, constructor_wrapper<Fxs...>>> { struct pusher<detail::tagged<T, constructor_wrapper<Fxs...>>> {
template <typename C> template <typename C>
static int push(lua_State* L, C&& c) { static int push(lua_State* L, C&& c) {
lua_CFunction cf = call_detail::call_user<T, false, false, constructor_wrapper<Fxs...>>; lua_CFunction cf = call_detail::call_user<T, false, false, constructor_wrapper<Fxs...>, 2>;
int closures = stack::push<user<constructor_wrapper<Fxs...>>>(L, std::forward<C>(c)); int upvalues = 0;
return stack::push(L, c_closure(cf, closures)); upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<constructor_wrapper<Fxs...>>>(L, std::forward<C>(c));
return stack::push(L, c_closure(cf, upvalues));
} }
}; };
@ -374,9 +396,11 @@ namespace sol {
template <typename T, typename Fx> template <typename T, typename Fx>
struct pusher<detail::tagged<T, destructor_wrapper<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>>; lua_CFunction cf = call_detail::call_user<T, false, false, destructor_wrapper<Fx>, 2>;
int closures = stack::push<user<T>>(L, std::move(c)); int upvalues = 0;
return stack::push(L, c_closure(cf, closures)); upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<T>>(L, std::move(c));
return stack::push(L, c_closure(cf, upvalues));
} }
}; };

View File

@ -28,9 +28,9 @@
namespace sol { namespace sol {
namespace function_detail { namespace function_detail {
template <typename Fx> template <typename Fx, int start = 1>
inline int call(lua_State* L) { inline int call(lua_State* L) {
Fx& fx = stack::get<user<Fx>>(L, upvalue_index(1)); Fx& fx = stack::get<user<Fx>>(L, upvalue_index(start));
return fx(L); return fx(L);
} }
} // function_detail } // function_detail

View File

@ -57,7 +57,7 @@ namespace sol {
// idx n + 1: is the object's void pointer // idx n + 1: is the object's void pointer
// We don't need to store the size, because the other side is templated // We don't need to store the size, because the other side is templated
// with the same member function pointer type // with the same member function pointer type
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1); auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L);
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;
@ -84,7 +84,7 @@ namespace sol {
// idx n + 1: is the object's void pointer // idx n + 1: is the object's void pointer
// We don't need to store the size, because the other side is templated // We don't need to store the size, because the other side is templated
// with the same member function pointer type // with the same member function pointer type
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1); auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L);
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second); auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
auto& mem = *objdata.first; auto& mem = *objdata.first;
function_type& var = memberdata.first; function_type& var = memberdata.first;
@ -115,7 +115,7 @@ namespace sol {
static int real_call(lua_State* L) { static int real_call(lua_State* L) {
// 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);
function_type& memfx = memberdata.first; function_type& memfx = memberdata.first;
return call_detail::call_wrapped<T, false, false>(L, memfx); return call_detail::call_wrapped<T, false, false>(L, memfx);
} }
@ -137,7 +137,7 @@ namespace sol {
static int real_call(lua_State* L) { static int real_call(lua_State* L) {
// 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);
function_type& var = memberdata.first; function_type& var = memberdata.first;
switch (lua_gettop(L)) { switch (lua_gettop(L)) {
case 1: case 1:

View File

@ -56,7 +56,7 @@ namespace sol {
} }
template<typename T> template<typename T>
inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 1) { inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 2) {
const static std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); const static std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*);
typedef std::array<void*, data_t_count> data_t; typedef std::array<void*, data_t_count> data_t;
data_t voiddata{ {} }; data_t voiddata{ {} };

View File

@ -136,6 +136,15 @@ namespace sol {
} }
}; };
template <typename C>
struct checker<this_environment, type::poly, C> {
template <typename Handler>
static bool check(lua_State*, int, Handler&&, record& tracking) {
tracking.use(0);
return true;
}
};
template <typename C> template <typename C>
struct checker<variadic_args, type::poly, C> { struct checker<variadic_args, type::poly, C> {
template <typename Handler> template <typename Handler>

View File

@ -633,6 +633,7 @@ namespace sol {
class thread; class thread;
struct variadic_args; struct variadic_args;
struct this_state; struct this_state;
struct this_environment;
namespace detail { namespace detail {
template <typename T, typename = void> template <typename T, typename = void>
@ -785,6 +786,9 @@ namespace sol {
template <> template <>
struct lua_type_of<this_state> : std::integral_constant<type, type::poly> {}; struct lua_type_of<this_state> : std::integral_constant<type, type::poly> {};
template <>
struct lua_type_of<this_environment> : std::integral_constant<type, type::poly> {};
template <> template <>
struct lua_type_of<type> : std::integral_constant<type, type::poly> {}; struct lua_type_of<type> : std::integral_constant<type, type::poly> {};
@ -901,6 +905,9 @@ namespace sol {
template <> template <>
struct is_transparent_argument<this_state> : std::true_type {}; struct is_transparent_argument<this_state> : std::true_type {};
template <>
struct is_transparent_argument<this_environment> : std::true_type {};
template <> template <>
struct is_transparent_argument<variadic_args> : std::true_type {}; struct is_transparent_argument<variadic_args> : std::true_type {};

View File

@ -201,3 +201,35 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
REQUIRE(!gtest.valid()); REQUIRE(!gtest.valid());
} }
} }
TEST_CASE("environments/this_environment", "test various situations of pulling out an environment") {
static std::string code = "return f(10)";
sol::state lua;
lua["f"] = [](sol::this_environment te, int x) {
if (te) {
sol::environment& env = te;
return x + static_cast<int>(env["x"]);
}
return x;
};
sol::environment e(lua, sol::create, lua.globals());
e["x"] = 20;
SECTION("from Lua script") {
int value = lua.script(code, e);
REQUIRE(value == 30);
}
SECTION("from C++") {
sol::function f = lua["f"];
e.set_on(f);
int value = f(10);
REQUIRE(value == 30);
}
SECTION("from C++, with no env") {
sol::function f = lua["f"];
int value = f(10);
REQUIRE(value == 10);
}
}