working stuff!~

This commit is contained in:
ThePhD 2017-04-19 13:00:47 -04:00
parent de7d7e8da5
commit a3d6f8044c
12 changed files with 307 additions and 94 deletions

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2017-04-19 00:25:59.958025 UTC // Generated 2017-04-19 16:59:23.068202 UTC
// This header was generated with sol v2.17.1 (revision 2acc8be) // This header was generated with sol v2.17.1 (revision de7d7e8)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP #ifndef SOL_SINGLE_INCLUDE_HPP
@ -3683,14 +3683,14 @@ namespace sol {
template <bool b, typename Base> template <bool b, typename Base>
struct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> { }; struct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> { };
template <typename B>
struct lua_type_of<basic_environment<B>> : std::integral_constant<type, type::table> { };
template <> template <>
struct lua_type_of<metatable_t> : std::integral_constant<type, type::table> { }; struct lua_type_of<metatable_t> : std::integral_constant<type, type::table> { };
template <typename B>
struct lua_type_of<basic_environment<B>> : std::integral_constant<type, type::poly> { };
template <> template <>
struct lua_type_of<env_t> : std::integral_constant<type, type::table> { }; struct lua_type_of<env_t> : std::integral_constant<type, type::poly> { };
template <> template <>
struct lua_type_of<new_table> : std::integral_constant<type, type::table> { }; struct lua_type_of<new_table> : std::integral_constant<type, type::table> { };
@ -3920,6 +3920,9 @@ namespace sol {
template <typename T> template <typename T>
struct is_userdata<basic_userdata<T>> : std::true_type {}; struct is_userdata<basic_userdata<T>> : std::true_type {};
template <typename T>
struct is_environment : std::integral_constant<bool, is_userdata<T>::value || is_table<T>::value> {};
template <typename T> template <typename T>
struct is_container : detail::is_container<T>{}; struct is_container : detail::is_container<T>{};
@ -4032,11 +4035,11 @@ namespace sol {
namespace sol { namespace sol {
namespace stack { namespace stack {
inline void remove(lua_State* L, int index, int count) { inline void remove(lua_State* L, int rawindex, int count) {
if (count < 1) if (count < 1)
return; return;
int top = lua_gettop(L); int top = lua_gettop(L);
if (index == -count || top == index) { if (rawindex == -count || top == rawindex) {
// Slice them right off the top // Slice them right off the top
lua_pop(L, static_cast<int>(count)); lua_pop(L, static_cast<int>(count));
return; return;
@ -4045,6 +4048,7 @@ namespace sol {
// Remove each item one at a time using stack operations // Remove each item one at a time using stack operations
// Probably slower, maybe, haven't benchmarked, // Probably slower, maybe, haven't benchmarked,
// but necessary // but necessary
int index = lua_absindex(L, rawindex);
if (index < 0) { if (index < 0) {
index = lua_gettop(L) + (index + 1); index = lua_gettop(L) + (index + 1);
} }
@ -4102,6 +4106,7 @@ namespace sol {
namespace detail { namespace detail {
struct global_tag { } const global_{}; struct global_tag { } const global_{};
struct no_safety_tag {} const no_safety;
} // detail } // detail
class reference { class reference {
@ -5188,6 +5193,14 @@ namespace sol {
} }
}; };
template <typename B, typename C>
struct checker<basic_userdata<B>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::check<userdata_value>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T, typename C> template <typename T, typename C>
struct checker<user<T>, type::userdata, C> : checker<user<T>, type::lightuserdata, C> {}; struct checker<user<T>, type::userdata, C> : checker<user<T>, type::lightuserdata, C> {};
@ -5258,6 +5271,28 @@ namespace sol {
template <type expected, typename C> template <type expected, typename C>
struct checker<metatable_t, expected, C> { struct checker<metatable_t, expected, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
if (lua_getmetatable(L, index) == 0) {
return true;
}
type t = type_of(L, -1);
if (t == type::table || t == type::none || t == type::nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, expected, t);
return false;
}
return true;
}
};
template <typename C>
struct checker<env_t, type::poly, C> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
@ -5278,8 +5313,8 @@ namespace sol {
} }
}; };
template <type expected, typename C> template <typename E, typename C>
struct checker<env_t, expected, C> { struct checker<basic_environment<E>, type::poly, C> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
@ -7500,21 +7535,21 @@ namespace sol {
basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {} basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<meta::unqualified_t<T>, ref_index>>> = meta::enabler> template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<meta::unqualified_t<T>, ref_index>>> = meta::enabler>
basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {} basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {}
basic_userdata(lua_State* L, int index = -1) : base_t(L, index) { basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
type_assert(L, index, type::userdata); stack::check<basic_userdata>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
basic_userdata(lua_State* L, ref_index index) : base_t(L, index) { basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
type_assert(L, -1, type::userdata); stack::check<basic_userdata>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
}; };
template <typename base_type> template <typename base_type>
class basic_lightuserdata : public basic_object_base< base_type > { class basic_lightuserdata : public basic_object_base<base_type> {
typedef basic_object_base<base_type> base_t; typedef basic_object_base<base_type> base_t;
public: public:
basic_lightuserdata() noexcept = default; basic_lightuserdata() noexcept = default;
@ -7537,13 +7572,13 @@ namespace sol {
basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {} basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {}
basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
type_assert(L, index, type::lightuserdata); stack::check<basic_lightuserdata>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
type_assert(L, -1, type::lightuserdata); stack::check<basic_lightuserdata>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
}; };
@ -10594,7 +10629,7 @@ namespace sol {
return stack::push(L, runtime[runtimetarget]); return stack::push(L, runtime[runtimetarget]);
} }
template <bool is_index> template <typename T, bool is_index>
inline int indexing_fail(lua_State* L) { inline int indexing_fail(lua_State* L) {
if (is_index) { if (is_index) {
#if 0//def SOL_SAFE_USERTYPE #if 0//def SOL_SAFE_USERTYPE
@ -10602,6 +10637,15 @@ namespace sol {
string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)"));
return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str()); return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str());
#else #else
int isnum = 0;
lua_Integer magic = lua_tointegerx(L, upvalue_index(4), &isnum);
if (isnum != 0 && magic == toplevel_magic) {
if (lua_getmetatable(L, 1) == 1) {
int metatarget = lua_gettop(L);
stack::get_field(L, stack_reference(L, raw_index(2)), metatarget);
return 1;
}
}
// With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately... // With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately...
return stack::push(L, lua_nil); return stack::push(L, lua_nil);
#endif #endif
@ -10641,34 +10685,40 @@ namespace sol {
} }
}; };
non_simple(); non_simple();
for (std::size_t i = 0; i < 4; lua_pop(L, 1), ++i) { for (std::size_t i = 0; i < 4; lua_settop(L, 3), ++i) {
const char* metakey = nullptr; const char* metakey = nullptr;
switch (i) { switch (i) {
case 0: case 0:
metakey = &usertype_traits<T*>::metatable()[0]; metakey = &usertype_traits<T*>::metatable()[0];
luaL_getmetatable(L, metakey);
break; break;
case 1: case 1:
metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0]; metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0];
luaL_getmetatable(L, metakey);
break; break;
case 2: case 2:
metakey = &usertype_traits<T>::user_metatable()[0]; metakey = &usertype_traits<T>::metatable()[0];
luaL_getmetatable(L, metakey);
break; break;
case 3: case 3:
default: default:
metakey = &usertype_traits<T>::metatable()[0]; metakey = &usertype_traits<T>::user_metatable()[0];
{
luaL_getmetatable(L, metakey);
lua_getmetatable(L, -1);
}
break; break;
} }
luaL_getmetatable(L, metakey);
int tableindex = lua_gettop(L); int tableindex = lua_gettop(L);
if (type_of(L, tableindex) == type::lua_nil) { if (type_of(L, tableindex) == type::lua_nil) {
continue; continue;
} }
stack::set_field<false, true>(L, stack_reference(L, 2), stack_reference(L, 3), tableindex); stack::set_field<false, true>(L, stack_reference(L, raw_index(2)), stack_reference(L, raw_index(3)), tableindex);
} }
lua_settop(L, 0); lua_settop(L, 0);
return 0; return 0;
} }
return indexing_fail<false>(L); return indexing_fail<T, false>(L);
} }
template <bool is_index, typename Base> template <bool is_index, typename Base>
@ -10877,7 +10927,7 @@ namespace sol {
} }
template <typename... Args, typename = std::enable_if_t<sizeof...(Args) == sizeof...(Tn)>> template <typename... Args, typename = std::enable_if_t<sizeof...(Args) == sizeof...(Tn)>>
usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail<true>, &usertype_detail::metatable_newindex<T, false>), usertype_detail::registrar(), usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail<T, true>, &usertype_detail::metatable_newindex<T, false>), usertype_detail::registrar(),
functions(std::forward<Args>(args)...), functions(std::forward<Args>(args)...),
destructfunc(nullptr), callconstructfunc(nullptr), destructfunc(nullptr), callconstructfunc(nullptr),
indexbase(&core_indexing_call<true>), newindexbase(&core_indexing_call<false>), indexbase(&core_indexing_call<true>), newindexbase(&core_indexing_call<false>),
@ -11408,7 +11458,7 @@ namespace sol {
template<std::size_t... I, typename Tuple> template<std::size_t... I, typename Tuple>
simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args) simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
: callconstructfunc(lua_nil), : callconstructfunc(lua_nil),
indexfunc(&usertype_detail::indexing_fail<true>), newindexfunc(&usertype_detail::metatable_newindex<T, true>), indexfunc(&usertype_detail::indexing_fail<T, true>), newindexfunc(&usertype_detail::metatable_newindex<T, true>),
indexbase(&usertype_detail::simple_core_indexing_call<true>), newindexbase(&usertype_detail::simple_core_indexing_call<false>), indexbase(&usertype_detail::simple_core_indexing_call<true>), newindexbase(&usertype_detail::simple_core_indexing_call<false>),
indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>), indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>),
baseclasscheck(nullptr), baseclasscast(nullptr), baseclasscheck(nullptr), baseclasscast(nullptr),
@ -12449,6 +12499,12 @@ namespace sol {
} }
basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { } basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { }
protected:
basic_table_core(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {}
basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {}
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward<T>(r)) {}
public: public:
typedef basic_table_iterator<base_type> iterator; typedef basic_table_iterator<base_type> iterator;
@ -12468,19 +12524,19 @@ namespace sol {
lua_pop(L, 1); lua_pop(L, 1);
} }
} }
basic_table_core(lua_State* L, int index = -1) : base_t(L, index) { basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_table_core>(L, index, type_panic); stack::check<basic_table_core>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
basic_table_core(lua_State* L, ref_index index) : base_t(L, index) { basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_table_core>(L, -1, type_panic); stack::check<basic_table_core>(L, -1, type_panic);
#endif // Safety #endif // Safety
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
basic_table_core(T&& r) noexcept : base_t(std::forward<T>(r)) { basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward<T>(r)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!is_table<meta::unqualified_t<T>>::value) { if (!is_table<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
@ -12800,35 +12856,57 @@ namespace sol {
template <typename base_type> template <typename base_type>
struct basic_environment : basic_table<base_type> { struct basic_environment : basic_table<base_type> {
private: private:
typedef basic_table<base_type> table_t; typedef basic_table<base_type> base_t;
public: public:
basic_environment() noexcept = default; basic_environment() noexcept = default;
basic_environment(const basic_environment&) = default; basic_environment(const basic_environment&) = default;
basic_environment(basic_environment&&) = default; basic_environment(basic_environment&&) = default;
basic_environment& operator=(const basic_environment&) = default; basic_environment& operator=(const basic_environment&) = default;
basic_environment& operator=(basic_environment&&) = default; basic_environment& operator=(basic_environment&&) = default;
basic_environment(const stack_reference& r) : basic_environment(r.lua_state(), r.stack_index()) {}
basic_environment(env_t, const stack_reference& extraction_target) : table_t(extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { basic_environment(stack_reference&& r) : basic_environment(r.lua_state(), r.stack_index()) {}
lua_pop(this->lua_state(), 2);
}
basic_environment(env_t, const reference& extraction_target) : table_t(extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
lua_pop(this->lua_state(), 2);
}
basic_environment(lua_State* L, new_table t, const reference& fallback) : table_t(L, std::move(t)) { basic_environment(lua_State* L, new_table nt) : base_t(L, std::move(nt)) {}
basic_environment(lua_State* L, new_table t, const reference& fallback) : basic_environment(L, std::move(t)) {
sol::stack_table mt(L, sol::new_table(0, 1)); sol::stack_table mt(L, sol::new_table(0, 1));
mt.set(sol::meta_function::index, fallback); mt.set(sol::meta_function::index, fallback);
this->set(metatable_key, mt); this->set(metatable_key, mt);
mt.pop(); mt.pop();
} }
template <typename T, typename... Args, meta::enable< basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
meta::neg<std::is_same<meta::unqualified_t<T>, basic_environment>>, #ifdef SOL_CHECK_ARGUMENTS
meta::boolean<!(sizeof...(Args) == 2 && meta::any_same<new_table, meta::unqualified_t<Args>...>::value)>, stack::check<env_t>(this->lua_state(), -1, type_panic);
meta::boolean<!(sizeof...(Args) == 1 && std::is_same<env_t, meta::unqualified_t<T>>::value)>, #endif // Safety
meta::boolean<!(sizeof...(Args) == 0 && std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>::value)> lua_pop(this->lua_state(), 2);
> = meta::enabler> }
basic_environment(T&& arg, Args&&... args) : table_t(std::forward<T>(arg), std::forward<Args>(args)...) { } basic_environment(env_t, const reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
#ifdef SOL_CHECK_ARGUMENTS
stack::check<env_t>(this->lua_state(), -1, type_panic);
#endif // Safety
lua_pop(this->lua_state(), 2);
}
basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_environment>(L, index, type_panic);
#endif // Safety
}
basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this);
stack::check<basic_environment>(L, -1, type_panic);
#endif // Safety
}
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
basic_environment(T&& r) noexcept : base_t(detail::no_safety, std::forward<T>(r)) {
#ifdef SOL_CHECK_ARGUMENTS
if (!is_environment<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this);
stack::check<basic_environment>(base_t::lua_state(), -1, type_panic);
}
#endif // Safety
}
template <typename T> template <typename T>
void set_on(const T& target) const { void set_on(const T& target) const {

View File

@ -29,35 +29,57 @@ namespace sol {
template <typename base_type> template <typename base_type>
struct basic_environment : basic_table<base_type> { struct basic_environment : basic_table<base_type> {
private: private:
typedef basic_table<base_type> table_t; typedef basic_table<base_type> base_t;
public: public:
basic_environment() noexcept = default; basic_environment() noexcept = default;
basic_environment(const basic_environment&) = default; basic_environment(const basic_environment&) = default;
basic_environment(basic_environment&&) = default; basic_environment(basic_environment&&) = default;
basic_environment& operator=(const basic_environment&) = default; basic_environment& operator=(const basic_environment&) = default;
basic_environment& operator=(basic_environment&&) = default; basic_environment& operator=(basic_environment&&) = default;
basic_environment(const stack_reference& r) : basic_environment(r.lua_state(), r.stack_index()) {}
basic_environment(env_t, const stack_reference& extraction_target) : table_t(extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { basic_environment(stack_reference&& r) : basic_environment(r.lua_state(), r.stack_index()) {}
lua_pop(this->lua_state(), 2);
}
basic_environment(env_t, const reference& extraction_target) : table_t(extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
lua_pop(this->lua_state(), 2);
}
basic_environment(lua_State* L, new_table t, const reference& fallback) : table_t(L, std::move(t)) { basic_environment(lua_State* L, new_table nt) : base_t(L, std::move(nt)) {}
basic_environment(lua_State* L, new_table t, const reference& fallback) : basic_environment(L, std::move(t)) {
sol::stack_table mt(L, sol::new_table(0, 1)); sol::stack_table mt(L, sol::new_table(0, 1));
mt.set(sol::meta_function::index, fallback); mt.set(sol::meta_function::index, fallback);
this->set(metatable_key, mt); this->set(metatable_key, mt);
mt.pop(); mt.pop();
} }
template <typename T, typename... Args, meta::enable< basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
meta::neg<std::is_same<meta::unqualified_t<T>, basic_environment>>, #ifdef SOL_CHECK_ARGUMENTS
meta::boolean<!(sizeof...(Args) == 2 && meta::any_same<new_table, meta::unqualified_t<Args>...>::value)>, stack::check<env_t>(this->lua_state(), -1, type_panic);
meta::boolean<!(sizeof...(Args) == 1 && std::is_same<env_t, meta::unqualified_t<T>>::value)>, #endif // Safety
meta::boolean<!(sizeof...(Args) == 0 && std::is_base_of<proxy_base_tag, meta::unqualified_t<T>>::value)> lua_pop(this->lua_state(), 2);
> = meta::enabler> }
basic_environment(T&& arg, Args&&... args) : table_t(std::forward<T>(arg), std::forward<Args>(args)...) { } basic_environment(env_t, const reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) {
#ifdef SOL_CHECK_ARGUMENTS
stack::check<env_t>(this->lua_state(), -1, type_panic);
#endif // Safety
lua_pop(this->lua_state(), 2);
}
basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_environment>(L, index, type_panic);
#endif // Safety
}
basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this);
stack::check<basic_environment>(L, -1, type_panic);
#endif // Safety
}
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
basic_environment(T&& r) noexcept : base_t(detail::no_safety, std::forward<T>(r)) {
#ifdef SOL_CHECK_ARGUMENTS
if (!is_environment<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this);
stack::check<basic_environment>(base_t::lua_state(), -1, type_panic);
}
#endif // Safety
}
template <typename T> template <typename T>
void set_on(const T& target) const { void set_on(const T& target) const {

View File

@ -27,11 +27,11 @@
namespace sol { namespace sol {
namespace stack { namespace stack {
inline void remove(lua_State* L, int index, int count) { inline void remove(lua_State* L, int rawindex, int count) {
if (count < 1) if (count < 1)
return; return;
int top = lua_gettop(L); int top = lua_gettop(L);
if (index == -count || top == index) { if (rawindex == -count || top == rawindex) {
// Slice them right off the top // Slice them right off the top
lua_pop(L, static_cast<int>(count)); lua_pop(L, static_cast<int>(count));
return; return;
@ -40,6 +40,7 @@ namespace sol {
// Remove each item one at a time using stack operations // Remove each item one at a time using stack operations
// Probably slower, maybe, haven't benchmarked, // Probably slower, maybe, haven't benchmarked,
// but necessary // but necessary
int index = lua_absindex(L, rawindex);
if (index < 0) { if (index < 0) {
index = lua_gettop(L) + (index + 1); index = lua_gettop(L) + (index + 1);
} }
@ -97,6 +98,7 @@ namespace sol {
namespace detail { namespace detail {
struct global_tag { } const global_{}; struct global_tag { } const global_{};
struct no_safety_tag {} const no_safety;
} // detail } // detail
class reference { class reference {

View File

@ -289,7 +289,7 @@ namespace sol {
template<std::size_t... I, typename Tuple> template<std::size_t... I, typename Tuple>
simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args) simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence<I...>, lua_State* L, Tuple&& args)
: callconstructfunc(lua_nil), : callconstructfunc(lua_nil),
indexfunc(&usertype_detail::indexing_fail<true>), newindexfunc(&usertype_detail::metatable_newindex<T, true>), indexfunc(&usertype_detail::indexing_fail<T, true>), newindexfunc(&usertype_detail::metatable_newindex<T, true>),
indexbase(&usertype_detail::simple_core_indexing_call<true>), newindexbase(&usertype_detail::simple_core_indexing_call<false>), indexbase(&usertype_detail::simple_core_indexing_call<true>), newindexbase(&usertype_detail::simple_core_indexing_call<false>),
indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>), indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>),
baseclasscheck(nullptr), baseclasscast(nullptr), baseclasscheck(nullptr), baseclasscast(nullptr),

View File

@ -198,6 +198,14 @@ namespace sol {
} }
}; };
template <typename B, typename C>
struct checker<basic_userdata<B>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack::check<userdata_value>(L, index, std::forward<Handler>(handler), tracking);
}
};
template <typename T, typename C> template <typename T, typename C>
struct checker<user<T>, type::userdata, C> : checker<user<T>, type::lightuserdata, C> {}; struct checker<user<T>, type::userdata, C> : checker<user<T>, type::lightuserdata, C> {};
@ -268,6 +276,28 @@ namespace sol {
template <type expected, typename C> template <type expected, typename C>
struct checker<metatable_t, expected, C> { struct checker<metatable_t, expected, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1);
if (lua_getmetatable(L, index) == 0) {
return true;
}
type t = type_of(L, -1);
if (t == type::table || t == type::none || t == type::nil) {
lua_pop(L, 1);
return true;
}
if (t != type::userdata) {
lua_pop(L, 1);
handler(L, index, expected, t);
return false;
}
return true;
}
};
template <typename C>
struct checker<env_t, type::poly, C> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);
@ -288,8 +318,8 @@ namespace sol {
} }
}; };
template <type expected, typename C> template <typename E, typename C>
struct checker<env_t, expected, C> { struct checker<basic_environment<E>, type::poly, C> {
template <typename Handler> template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
tracking.use(1); tracking.use(1);

View File

@ -156,6 +156,12 @@ namespace sol {
} }
basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { } basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { }
protected:
basic_table_core(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {}
basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {}
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward<T>(r)) {}
public: public:
typedef basic_table_iterator<base_type> iterator; typedef basic_table_iterator<base_type> iterator;
@ -175,19 +181,19 @@ namespace sol {
lua_pop(L, 1); lua_pop(L, 1);
} }
} }
basic_table_core(lua_State* L, int index = -1) : base_t(L, index) { basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_table_core>(L, index, type_panic); stack::check<basic_table_core>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
basic_table_core(lua_State* L, ref_index index) : base_t(L, index) { basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
stack::check<basic_table_core>(L, -1, type_panic); stack::check<basic_table_core>(L, -1, type_panic);
#endif // Safety #endif // Safety
} }
template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler> template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_table_core>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
basic_table_core(T&& r) noexcept : base_t(std::forward<T>(r)) { basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward<T>(r)) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
if (!is_table<meta::unqualified_t<T>>::value) { if (!is_table<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);

View File

@ -704,14 +704,14 @@ namespace sol {
template <bool b, typename Base> template <bool b, typename Base>
struct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> { }; struct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> { };
template <typename B>
struct lua_type_of<basic_environment<B>> : std::integral_constant<type, type::table> { };
template <> template <>
struct lua_type_of<metatable_t> : std::integral_constant<type, type::table> { }; struct lua_type_of<metatable_t> : std::integral_constant<type, type::table> { };
template <typename B>
struct lua_type_of<basic_environment<B>> : std::integral_constant<type, type::poly> { };
template <> template <>
struct lua_type_of<env_t> : std::integral_constant<type, type::table> { }; struct lua_type_of<env_t> : std::integral_constant<type, type::poly> { };
template <> template <>
struct lua_type_of<new_table> : std::integral_constant<type, type::table> { }; struct lua_type_of<new_table> : std::integral_constant<type, type::table> { };
@ -941,6 +941,9 @@ namespace sol {
template <typename T> template <typename T>
struct is_userdata<basic_userdata<T>> : std::true_type {}; struct is_userdata<basic_userdata<T>> : std::true_type {};
template <typename T>
struct is_environment : std::integral_constant<bool, is_userdata<T>::value || is_table<T>::value> {};
template <typename T> template <typename T>
struct is_container : detail::is_container<T>{}; struct is_container : detail::is_container<T>{};

View File

@ -48,21 +48,21 @@ namespace sol {
basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {} basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<meta::unqualified_t<T>, ref_index>>> = meta::enabler> template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<meta::unqualified_t<T>, ref_index>>> = meta::enabler>
basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {} basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {}
basic_userdata(lua_State* L, int index = -1) : base_t(L, index) { basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
type_assert(L, index, type::userdata); stack::check<basic_userdata>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
basic_userdata(lua_State* L, ref_index index) : base_t(L, index) { basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
type_assert(L, -1, type::userdata); stack::check<basic_userdata>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
}; };
template <typename base_type> template <typename base_type>
class basic_lightuserdata : public basic_object_base< base_type > { class basic_lightuserdata : public basic_object_base<base_type> {
typedef basic_object_base<base_type> base_t; typedef basic_object_base<base_type> base_t;
public: public:
basic_lightuserdata() noexcept = default; basic_lightuserdata() noexcept = default;
@ -85,13 +85,13 @@ namespace sol {
basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {} basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {}
basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
type_assert(L, index, type::lightuserdata); stack::check<basic_lightuserdata>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS #ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this); auto pp = stack::push_pop(*this);
type_assert(L, -1, type::lightuserdata); stack::check<basic_lightuserdata>(L, index, type_panic);
#endif // Safety #endif // Safety
} }
}; };

View File

@ -176,7 +176,7 @@ namespace sol {
return stack::push(L, runtime[runtimetarget]); return stack::push(L, runtime[runtimetarget]);
} }
template <bool is_index> template <typename T, bool is_index>
inline int indexing_fail(lua_State* L) { inline int indexing_fail(lua_State* L) {
if (is_index) { if (is_index) {
#if 0//def SOL_SAFE_USERTYPE #if 0//def SOL_SAFE_USERTYPE
@ -184,6 +184,15 @@ namespace sol {
string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)"));
return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str()); return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str());
#else #else
int isnum = 0;
lua_Integer magic = lua_tointegerx(L, upvalue_index(4), &isnum);
if (isnum != 0 && magic == toplevel_magic) {
if (lua_getmetatable(L, 1) == 1) {
int metatarget = lua_gettop(L);
stack::get_field(L, stack_reference(L, raw_index(2)), metatarget);
return 1;
}
}
// With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately... // With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately...
return stack::push(L, lua_nil); return stack::push(L, lua_nil);
#endif #endif
@ -223,34 +232,40 @@ namespace sol {
} }
}; };
non_simple(); non_simple();
for (std::size_t i = 0; i < 4; lua_pop(L, 1), ++i) { for (std::size_t i = 0; i < 4; lua_settop(L, 3), ++i) {
const char* metakey = nullptr; const char* metakey = nullptr;
switch (i) { switch (i) {
case 0: case 0:
metakey = &usertype_traits<T*>::metatable()[0]; metakey = &usertype_traits<T*>::metatable()[0];
luaL_getmetatable(L, metakey);
break; break;
case 1: case 1:
metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0]; metakey = &usertype_traits<detail::unique_usertype<T>>::metatable()[0];
luaL_getmetatable(L, metakey);
break; break;
case 2: case 2:
metakey = &usertype_traits<T>::user_metatable()[0]; metakey = &usertype_traits<T>::metatable()[0];
luaL_getmetatable(L, metakey);
break; break;
case 3: case 3:
default: default:
metakey = &usertype_traits<T>::metatable()[0]; metakey = &usertype_traits<T>::user_metatable()[0];
{
luaL_getmetatable(L, metakey);
lua_getmetatable(L, -1);
}
break; break;
} }
luaL_getmetatable(L, metakey);
int tableindex = lua_gettop(L); int tableindex = lua_gettop(L);
if (type_of(L, tableindex) == type::lua_nil) { if (type_of(L, tableindex) == type::lua_nil) {
continue; continue;
} }
stack::set_field<false, true>(L, stack_reference(L, 2), stack_reference(L, 3), tableindex); stack::set_field<false, true>(L, stack_reference(L, raw_index(2)), stack_reference(L, raw_index(3)), tableindex);
} }
lua_settop(L, 0); lua_settop(L, 0);
return 0; return 0;
} }
return indexing_fail<false>(L); return indexing_fail<T, false>(L);
} }
template <bool is_index, typename Base> template <bool is_index, typename Base>
@ -459,7 +474,7 @@ namespace sol {
} }
template <typename... Args, typename = std::enable_if_t<sizeof...(Args) == sizeof...(Tn)>> template <typename... Args, typename = std::enable_if_t<sizeof...(Args) == sizeof...(Tn)>>
usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail<true>, &usertype_detail::metatable_newindex<T, false>), usertype_detail::registrar(), usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail<T, true>, &usertype_detail::metatable_newindex<T, false>), usertype_detail::registrar(),
functions(std::forward<Args>(args)...), functions(std::forward<Args>(args)...),
destructfunc(nullptr), callconstructfunc(nullptr), destructfunc(nullptr), callconstructfunc(nullptr),
indexbase(&core_indexing_call<true>), newindexbase(&core_indexing_call<false>), indexbase(&core_indexing_call<true>), newindexbase(&core_indexing_call<false>),

View File

@ -35,6 +35,8 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
sol::object global_test = lua["test"]; sol::object global_test = lua["test"];
REQUIRE(!global_test.valid()); REQUIRE(!global_test.valid());
lua.script("h = function() end");
lua.set_function("check_f_env", lua.set_function("check_f_env",
[&lua, &env_f](sol::object target) { [&lua, &env_f](sol::object target) {
sol::stack_guard sg(lua); sol::stack_guard sg(lua);
@ -57,10 +59,18 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
REQUIRE(env_g == target_env); REQUIRE(env_g == target_env);
} }
); );
lua.set_function("check_h_env",
[&lua](sol::function target) {
sol::stack_guard sg(lua);
sol::environment target_env = sol::get_environment(target);
REQUIRE_FALSE(target_env.valid());
}
);
REQUIRE_NOTHROW([&lua]() { REQUIRE_NOTHROW([&lua]() {
lua.script("check_f_env(f)"); lua.script("check_f_env(f)");
lua.script("check_g_env(g)"); lua.script("check_g_env(g)");
lua.script("check_h_env(h)");
}()); }());
} }

View File

@ -697,6 +697,30 @@ end
} }
} }
TEST_CASE("simple_usertype/runtime-replacement", "ensure that functions can be properly replaced at runtime for non-indexed things") {
struct heart_t {};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<heart_t>("a");
REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()");
}());
int v1 = lua["v1"];
int v2 = lua["v2"];
int v3 = lua["v3"];
REQUIRE(v1 == 1);
REQUIRE(v2 == 2);
REQUIRE(v3 == 3);
}
TEST_CASE("simple_usertype/meta-key-retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") { TEST_CASE("simple_usertype/meta-key-retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") {
SECTION("dynamically") { SECTION("dynamically") {
static int writes = 0; static int writes = 0;

View File

@ -523,10 +523,9 @@ TEST_CASE("usertype/nonmember-functions", "let users set non-member functions th
"gief_stuff", giver::gief_stuff, "gief_stuff", giver::gief_stuff,
"gief", &giver::gief, "gief", &giver::gief,
"__tostring", [](const giver& t) { "__tostring", [](const giver& t) {
return std::to_string(t.a) + ": giving value"; return std::to_string(t.a) + ": giving value";
} }
).get<sol::table>("giver") ).get<sol::table>("giver").set_function("stuff", giver::stuff);
.set_function("stuff", giver::stuff);
REQUIRE_NOTHROW(lua.script("giver.stuff()")); REQUIRE_NOTHROW(lua.script("giver.stuff()"));
REQUIRE_NOTHROW(lua.script("t = giver.new()\n" REQUIRE_NOTHROW(lua.script("t = giver.new()\n"
@ -1623,6 +1622,30 @@ end
} }
} }
TEST_CASE("usertype/runtime-replacement", "ensure that functions can be properly replaced at runtime for non-indexed things") {
struct heart_t {};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<heart_t>("a");
REQUIRE_NOTHROW([&lua]() {
lua.script("obj = a.new()");
lua.script("function a:heartbeat () print('arf') return 1 end");
lua.script("v1 = obj:heartbeat()");
lua.script("function a:heartbeat () print('bark') return 2 end");
lua.script("v2 = obj:heartbeat()");
lua.script("a.heartbeat = function(self) print('woof') return 3 end");
lua.script("v3 = obj:heartbeat()");
}());
int v1 = lua["v1"];
int v2 = lua["v2"];
int v3 = lua["v3"];
REQUIRE(v1 == 1);
REQUIRE(v2 == 2);
REQUIRE(v3 == 3);
}
TEST_CASE("usertype/meta-key-retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") { TEST_CASE("usertype/meta-key-retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") {
SECTION("dynamically") { SECTION("dynamically") {
static int writes = 0; static int writes = 0;