mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
sol::property is implemented for usertypes now
sol::this_state is a transparent argument that gets the current state at any position in any callback sol::variadic_args allows a person to get something that can reference the "rest of the arguments", though it doesn't enforce that it has to be the last argument Closes #57 Closes #59 Closes #60
This commit is contained in:
parent
f10988363c
commit
88155d44e0
@ -33,7 +33,6 @@
|
||||
#include "resolve.hpp"
|
||||
|
||||
namespace sol {
|
||||
|
||||
template <typename Sig, typename... Ps>
|
||||
struct function_arguments {
|
||||
std::tuple<Ps...> params;
|
||||
|
@ -80,7 +80,7 @@ struct upvalue_member_function {
|
||||
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, "cannot write to this type: copy assignment/constructor not available");
|
||||
return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available");
|
||||
}
|
||||
|
||||
template <int N, typename R, typename M, typename V>
|
||||
@ -98,7 +98,7 @@ int set_variable(std::true_type, lua_State* L, M& mem, V& 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, "cannot write to a const variable");
|
||||
return luaL_error(L, "sol: cannot write to a const variable");
|
||||
}
|
||||
|
||||
template<typename T, typename Function>
|
||||
|
@ -26,6 +26,108 @@
|
||||
#include <memory>
|
||||
|
||||
namespace sol {
|
||||
template <typename RSig = void, typename WSig = void>
|
||||
struct member_property {
|
||||
typedef std::conditional_t<std::is_void<RSig>::value, detail::empty, RSig> R;
|
||||
typedef std::conditional_t<std::is_void<WSig>::value, detail::empty, WSig> W;
|
||||
|
||||
R read;
|
||||
W write;
|
||||
|
||||
member_property(R read, W write) : read(std::move(read)), write(std::move(write)) {}
|
||||
|
||||
template <typename T, typename Arg>
|
||||
void write_if(std::true_type, T& mem, Arg&& arg) {
|
||||
write(mem, arg);
|
||||
}
|
||||
|
||||
template <typename T, typename Arg>
|
||||
void write_if(std::false_type, T&, Arg&&) {
|
||||
// This is a fatal error if we get here...
|
||||
// Should never happen but...
|
||||
// Crash horrifically, for safety?
|
||||
std::abort();
|
||||
}
|
||||
|
||||
template <typename T, typename Arg>
|
||||
void operator()(T& mem, Arg&& arg) {
|
||||
write_if(meta::Not<std::is_void<WSig>>(), mem, arg);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
decltype(auto) read_if(std::true_type, T& mem) {
|
||||
return read(mem);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
decltype(auto) read_if(std::false_type, T&) {
|
||||
typedef typename meta::bind_traits<WSig>::template arg_at<1> Arg;
|
||||
typedef std::add_pointer_t<std::remove_reference_t<Arg>> pret;
|
||||
// This is a fatal error if we get here...
|
||||
// Should never happen but...
|
||||
// Crash horrifically, for safety?
|
||||
std::abort();
|
||||
return *pret();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
decltype(auto) operator()(T& mem) {
|
||||
return read_if(meta::Not<std::is_void<RSig>>(), mem);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename R, typename T>
|
||||
inline decltype(auto) property( R(T::* readfunc )() const) {
|
||||
auto rf = [readfunc](T& mem) -> R {return (mem.*readfunc)();};
|
||||
return member_property<decltype(rf)>(std::move(rf), detail::empty());
|
||||
}
|
||||
|
||||
template <typename R, typename T>
|
||||
inline decltype(auto) property( R(T::* readfunc )()) {
|
||||
auto rf = [readfunc](T& mem) -> R {return (mem.*readfunc)();};
|
||||
return member_property<decltype(rf)>(std::move(rf), detail::empty());
|
||||
}
|
||||
|
||||
template <typename R, typename T, typename Arg>
|
||||
inline decltype(auto) property(R(T::* writefunc)(Arg)) {
|
||||
auto wf = [writefunc](T& mem, Arg arg) {(mem.*writefunc)(std::forward<Arg>(arg));};
|
||||
return member_property<void, decltype(wf)>(detail::empty(), std::move(wf));
|
||||
}
|
||||
|
||||
template <typename R, typename T, typename Arg>
|
||||
inline decltype(auto) property(R(T::* writefunc)(Arg) const) {
|
||||
auto wf = [writefunc](T& mem, Arg arg) {(mem.*writefunc)(std::forward<Arg>(arg));};
|
||||
return member_property<void, decltype(wf)>(detail::empty(), std::move(wf));
|
||||
}
|
||||
|
||||
template <typename RR, typename RT, typename WR, typename WT, typename Arg>
|
||||
inline decltype(auto) property(RR(RT::* readfunc)(), WR(WT::* writefunc)(Arg)) {
|
||||
auto rf = [readfunc](RT& mem) -> RR {return (mem.*readfunc)();};
|
||||
auto wf = [writefunc](WT& mem, Arg arg) {(mem.*writefunc)(std::forward<Arg>(arg));};
|
||||
return member_property<decltype(rf), decltype(wf)>(std::move(rf), std::move(wf));
|
||||
}
|
||||
|
||||
template <typename RR, typename RT, typename WR, typename WT, typename Arg>
|
||||
inline decltype(auto) property(RR(RT::* readfunc)() const, WR(WT::* writefunc)(Arg)) {
|
||||
auto rf = [readfunc](RT& mem) -> RR {return (mem.*readfunc)();};
|
||||
auto wf = [writefunc](WT& mem, Arg arg) {(mem.*writefunc)(std::forward<Arg>(arg));};
|
||||
return member_property<decltype(rf), decltype(wf)>(std::move(rf), std::move(wf));
|
||||
}
|
||||
|
||||
template <typename RR, typename RT, typename WR, typename WT, typename Arg>
|
||||
inline decltype(auto) property(RR(RT::* readfunc)(), WR(WT::* writefunc)(Arg) const) {
|
||||
auto rf = [readfunc](RT& mem) -> RR {return (mem.*readfunc)();};
|
||||
auto wf = [writefunc](WT& mem, Arg arg) {(mem.*writefunc)(std::forward<Arg>(arg));};
|
||||
return member_property<decltype(rf), decltype(wf)>(std::move(rf), std::move(wf));
|
||||
}
|
||||
|
||||
template <typename RR, typename RT, typename WR, typename WT, typename Arg>
|
||||
inline decltype(auto) property(RR(RT::* readfunc)() const, WR(WT::* writefunc)(Arg) const) {
|
||||
auto rf = [readfunc](RT& mem) -> RR {return (mem.*readfunc)();};
|
||||
auto wf = [writefunc](WT& mem, Arg arg) {(mem.*writefunc)(std::forward<Arg>(arg));};
|
||||
return member_property<decltype(rf), decltype(wf)>(std::move(rf), std::move(wf));
|
||||
}
|
||||
|
||||
namespace function_detail {
|
||||
template <typename T>
|
||||
struct implicit_wrapper {
|
||||
@ -48,35 +150,62 @@ inline decltype(auto) cleanup_key() {
|
||||
template<typename T, typename Func, typename = void>
|
||||
struct functor {
|
||||
typedef meta::bind_traits<Func> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef meta::pop_front_type_t<typename traits_type::args_type> args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
static const std::size_t arity = traits_type::arity;
|
||||
|
||||
typedef meta::tuple_element_t<0, typename traits_type::args_tuple_type> Arg0;
|
||||
typedef std::conditional_t<std::is_pointer<Func>::value || std::is_class<Func>::value, Func, std::add_pointer_t<Func>> function_type;
|
||||
T* item;
|
||||
Func invocation;
|
||||
function_type invocation;
|
||||
|
||||
template<typename... Args>
|
||||
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
||||
|
||||
bool check () const {
|
||||
return invocation != nullptr;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void call(types<void>, Args&&... args) {
|
||||
T& member = *item;
|
||||
(member.*invocation)(std::forward<Args>(args)...);
|
||||
invocation(implicit_wrapper<T>(member), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
Ret call(types<Ret>, Args&&... args) {
|
||||
T& member = *item;
|
||||
return (member.*invocation)(std::forward<Args>(args)...);
|
||||
return invocation(implicit_wrapper<T>(member), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args) -> decltype(std::declval<functor>().call(types<return_type>{}, std::forward<Args>(args)...)) {
|
||||
return this->call(types<return_type>(), std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename RSig, typename WSig, typename C>
|
||||
struct functor<T, member_property<RSig, WSig>, C> {
|
||||
typedef meta::bind_traits<std::conditional_t<std::is_void<WSig>::value, RSig, WSig>> traits_type;
|
||||
typedef meta::pop_front_type_t<typename traits_type::args_type> args_type;
|
||||
typedef std::conditional_t<std::is_void<typename traits_type::return_type>::value, typename traits_type::template arg_at<0>, typename traits_type::return_type> return_type;
|
||||
typedef member_property<RSig, WSig> function_type;
|
||||
typedef meta::Not<std::is_void<RSig>> can_read;
|
||||
typedef meta::Not<std::is_void<WSig>> can_write;
|
||||
T* item;
|
||||
function_type invocation;
|
||||
|
||||
template<typename... Args>
|
||||
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename Arg>
|
||||
void call(Arg&& arg) {
|
||||
T& member = *item;
|
||||
invocation(member, std::forward<Arg>(arg));
|
||||
}
|
||||
|
||||
decltype(auto) call() {
|
||||
T& member = *item;
|
||||
return invocation(member);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
decltype(auto) operator()(Args&&... args) {
|
||||
return this->call(types<return_type>{}, std::forward<Args>(args)...);
|
||||
return this->call(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
@ -86,16 +215,15 @@ struct functor<T, Func, std::enable_if_t<std::is_member_object_pointer<Func>::va
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
static const std::size_t arity = traits_type::arity;
|
||||
typedef std::true_type can_read;
|
||||
typedef std::true_type can_write;
|
||||
|
||||
T* item;
|
||||
Func invocation;
|
||||
|
||||
template<typename... Args>
|
||||
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
||||
|
||||
bool check () const {
|
||||
return this->fx.invocation != nullptr;
|
||||
}
|
||||
|
||||
template<typename Arg>
|
||||
void call(Arg&& arg) {
|
||||
T& member = *item;
|
||||
@ -114,50 +242,33 @@ struct functor<T, Func, std::enable_if_t<std::is_member_object_pointer<Func>::va
|
||||
};
|
||||
|
||||
template<typename T, typename Func>
|
||||
struct functor<T, Func, std::enable_if_t<std::is_function<Func>::value || std::is_class<Func>::value>> {
|
||||
struct functor<T, Func, std::enable_if_t<std::is_member_function_pointer<Func>::value>> {
|
||||
typedef meta::bind_traits<Func> traits_type;
|
||||
typedef meta::pop_front_type_t<typename traits_type::args_type> args_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
static const std::size_t arity = traits_type::arity;
|
||||
typedef meta::tuple_element_t<0, typename traits_type::args_tuple_type> Arg0;
|
||||
typedef std::conditional_t<std::is_pointer<Func>::value || std::is_class<Func>::value, Func, std::add_pointer_t<Func>> function_type;
|
||||
static_assert(std::is_base_of<meta::Unqualified<std::remove_pointer_t<Arg0>>, T>::value, "Any non-member-function must have a first argument which is covariant with the desired userdata type.");
|
||||
|
||||
T* item;
|
||||
function_type invocation;
|
||||
|
||||
private:
|
||||
bool check(std::false_type) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check(std::true_type) const {
|
||||
return this->invocation != nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
Func invocation;
|
||||
|
||||
template<typename... Args>
|
||||
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
||||
|
||||
bool check () const {
|
||||
return this->check(std::is_function<Func>());
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void call(types<void>, Args&&... args) {
|
||||
T& member = *item;
|
||||
invocation(implicit_wrapper<T>(member), std::forward<Args>(args)...);
|
||||
(member.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
Ret call(types<Ret>, Args&&... args) {
|
||||
T& member = *item;
|
||||
return invocation(implicit_wrapper<T>(member), std::forward<Args>(args)...);
|
||||
return (member.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args) -> decltype(std::declval<functor>().call(types<return_type>{}, std::forward<Args>(args)...)) {
|
||||
return this->call(types<return_type>(), std::forward<Args>(args)...);
|
||||
decltype(auto) operator()(Args&&... args) {
|
||||
return this->call(types<return_type>{}, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -113,7 +113,7 @@ struct member_variable : public base_function {
|
||||
|
||||
int set_assignable(std::false_type, lua_State* L, M) {
|
||||
lua_pop(L, 1);
|
||||
return luaL_error(L, "cannot write to this type: copy assignment/constructor not available");
|
||||
return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available");
|
||||
}
|
||||
|
||||
int set_assignable(std::true_type, lua_State* L, M mem) {
|
||||
@ -128,7 +128,7 @@ struct member_variable : public base_function {
|
||||
|
||||
int set_variable(std::false_type, lua_State* L, M) {
|
||||
lua_pop(L, 1);
|
||||
return luaL_error(L, "cannot write to a const variable");
|
||||
return luaL_error(L, "sol: cannot write to a const variable");
|
||||
}
|
||||
|
||||
int call(lua_State* L) {
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
namespace sol {
|
||||
namespace function_detail {
|
||||
template<typename Function, typename Tp>
|
||||
template<typename Tp, typename Function>
|
||||
struct usertype_function_core : public base_function {
|
||||
typedef std::remove_pointer_t<Tp> T;
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
@ -42,48 +42,15 @@ struct usertype_function_core : public base_function {
|
||||
template<typename... Args>
|
||||
usertype_function_core(Args&&... args): fx(std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename Return, typename Raw = meta::Unqualified<Return>>
|
||||
std::enable_if_t<std::is_same<T, Raw>::value, int> push(lua_State* L, Return&& r) {
|
||||
if(detail::ptr(detail::unwrap(r)) == fx.item) {
|
||||
// push nothing
|
||||
// note that pushing nothing with the ':'
|
||||
// syntax means we leave the instance of what
|
||||
// was pushed onto the stack by lua to do the
|
||||
// function call alone,
|
||||
// and naturally lua returns that.
|
||||
// It's an "easy" way to return *this,
|
||||
// without allocating an extra userdata, apparently!
|
||||
return 1;
|
||||
}
|
||||
return stack::push_reference(L, std::forward<Return>(r));
|
||||
}
|
||||
|
||||
template<typename Return, typename Raw = meta::Unqualified<Return>>
|
||||
std::enable_if_t<!std::is_same<T, Raw>::value, int> push(lua_State* L, Return&& r) {
|
||||
return stack::push_reference(L, std::forward<Return>(r));
|
||||
}
|
||||
|
||||
template<typename... Args, std::size_t Start>
|
||||
int operator()(types<void> tr, types<Args...> ta, index_value<Start>, lua_State* L) {
|
||||
stack::call_into_lua(tr, ta, L, static_cast<int>(Start), fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args, std::size_t Start>
|
||||
int operator()(types<Ret...> tr, types<Args...> ta, index_value<Start>, lua_State* L) {
|
||||
decltype(auto) r = stack::call(tr, ta, L, static_cast<int>(Start), fx);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
lua_pop(L, nargs);
|
||||
int pushcount = push(L, std::forward<decltype(r)>(r));
|
||||
return pushcount;
|
||||
return stack::call_into_lua<1>(tr, ta, L, static_cast<int>(Start), fx);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename Tp>
|
||||
struct usertype_function : public usertype_function_core<Function, Tp> {
|
||||
typedef usertype_function_core<Function, Tp> base_t;
|
||||
template<typename Tp, typename Function>
|
||||
struct usertype_function : public usertype_function_core<Tp, Function> {
|
||||
typedef usertype_function_core<Tp, Function> base_t;
|
||||
typedef std::remove_pointer_t<Tp> T;
|
||||
typedef typename base_t::traits_type traits_type;
|
||||
typedef typename base_t::args_type args_type;
|
||||
@ -102,41 +69,62 @@ struct usertype_function : public usertype_function_core<Function, Tp> {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename Tp>
|
||||
struct usertype_variable_function : public usertype_function_core<Function, Tp> {
|
||||
typedef usertype_function_core<Function, Tp> base_t;
|
||||
template<typename Tp, typename Function>
|
||||
struct usertype_variable_function : public usertype_function_core<Tp, Function> {
|
||||
typedef usertype_function_core<Tp, Function> base_t;
|
||||
typedef std::remove_pointer_t<Tp> T;
|
||||
typedef typename base_t::fx_t fx_t;
|
||||
typedef typename base_t::traits_type traits_type;
|
||||
typedef typename base_t::args_type args_type;
|
||||
typedef typename base_t::return_type return_type;
|
||||
typedef typename fx_t::can_read can_read;
|
||||
typedef typename fx_t::can_write can_write;
|
||||
|
||||
template<typename... Args>
|
||||
usertype_variable_function(Args&&... args): base_t(std::forward<Args>(args)...) {}
|
||||
|
||||
int set_assignable(std::false_type, lua_State* L) {
|
||||
lua_pop(L, 2);
|
||||
return luaL_error(L, "cannot write to this type: copy assignment/constructor not available");
|
||||
lua_pop(L, 3);
|
||||
return luaL_error(L, "sol: cannot write to this type: copy assignment/constructor not available");
|
||||
}
|
||||
|
||||
int set_assignable(std::true_type, lua_State* L) {
|
||||
return set_writable(can_write(), L);
|
||||
}
|
||||
|
||||
int set_writable(std::false_type, lua_State* L) {
|
||||
lua_pop(L, 3);
|
||||
return luaL_error(L, "sol: cannot write to readonly variable");
|
||||
}
|
||||
|
||||
int set_writable(std::true_type, lua_State* L) {
|
||||
return static_cast<base_t&>(*this)(meta::tuple_types<void>(), args_type(), index_value<3>(), L);
|
||||
}
|
||||
|
||||
int set_variable(std::false_type, lua_State* L) {
|
||||
lua_pop(L, 2);
|
||||
return luaL_error(L, "cannot write to a const variable");
|
||||
lua_pop(L, 3);
|
||||
return luaL_error(L, "sol: cannot write to a const variable");
|
||||
}
|
||||
|
||||
int set_variable(std::true_type, lua_State* L) {
|
||||
return set_assignable(std::is_assignable<std::add_lvalue_reference_t<return_type>, return_type>(), L);
|
||||
}
|
||||
|
||||
int get_variable(std::false_type, lua_State* L) {
|
||||
lua_pop(L, 2);
|
||||
return luaL_error(L, "sol: cannot read from a readonly property");
|
||||
}
|
||||
|
||||
int get_variable(std::true_type, lua_State* L) {
|
||||
return static_cast<base_t&>(*this)(meta::tuple_types<return_type>(), types<>(), index_value<2>(), L);
|
||||
}
|
||||
|
||||
int prelude(lua_State* L) {
|
||||
int argcount = lua_gettop(L);
|
||||
this->fx.item = stack::get<T*>(L, 1);
|
||||
switch(argcount) {
|
||||
case 2:
|
||||
return static_cast<base_t&>(*this)(meta::tuple_types<return_type>(), types<>(), index_value<2>(), L);
|
||||
return get_variable(can_read(), L);
|
||||
case 3:
|
||||
return set_variable(meta::Not<std::is_const<return_type>>(), L);
|
||||
default:
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "reference.hpp"
|
||||
#include "userdata.hpp"
|
||||
#include "stack.hpp"
|
||||
#include "variadic_args.hpp"
|
||||
|
||||
namespace sol {
|
||||
template <typename base_t>
|
||||
|
@ -69,14 +69,18 @@ inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 1) {
|
||||
|
||||
template <bool checkargs = default_check_arguments, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
|
||||
inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
|
||||
typedef meta::index_in_pack<this_state, Args...> state_pack_index;
|
||||
typedef std::integral_constant<int, state_pack_index::value == -1 ? std::numeric_limits<int>::max() : static_cast<int>(state_pack_index::value)> state_idx;
|
||||
check_types<checkargs>{}.check(ta, tai, L, start, type_panic);
|
||||
return fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I)...);
|
||||
return fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + (state_idx::value < I ? I - 1 : I))...);
|
||||
}
|
||||
|
||||
template <bool checkargs = default_check_arguments, std::size_t... I, typename... Args, typename Fx, typename... FxArgs>
|
||||
inline void call(types<void>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
|
||||
typedef meta::index_in_pack<this_state, Args...> state_pack_index;
|
||||
typedef std::integral_constant<int, state_pack_index::value == -1 ? std::numeric_limits<int>::max() : static_cast<int>(state_pack_index::value)> state_idx;
|
||||
check_types<checkargs>{}.check(ta, tai, L, start, type_panic);
|
||||
fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I)...);
|
||||
fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + (state_idx::value < I ? I - 1 : I))...);
|
||||
}
|
||||
} // stack_detail
|
||||
|
||||
@ -104,7 +108,7 @@ inline void remove( lua_State* L, int index, int count ) {
|
||||
|
||||
template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
|
||||
inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
|
||||
typedef typename types<Args...>::indices args_indices;
|
||||
typedef std::make_index_sequence<sizeof...(Args)> args_indices;
|
||||
return stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
|
||||
}
|
||||
|
||||
@ -115,7 +119,7 @@ inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx
|
||||
|
||||
template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
|
||||
inline void call(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
|
||||
typedef typename types<Args...>::indices args_indices;
|
||||
typedef std::make_index_sequence<sizeof...(Args)> args_indices;
|
||||
stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
|
||||
}
|
||||
|
||||
@ -147,11 +151,11 @@ inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, i
|
||||
decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
|
||||
int nargs = static_cast<int>(sizeof...(Args)) + additionalpop;
|
||||
lua_pop(L, nargs);
|
||||
return push(L, std::forward<decltype(r)>(r));
|
||||
return push_reference(L, std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
||||
inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) {
|
||||
luaL_getmetatable(L, meta.c_str());
|
||||
inline call_syntax get_call_syntax(lua_State* L, const std::string& key) {
|
||||
luaL_getmetatable(L, key.c_str());
|
||||
if (lua_compare(L, -1, -2, LUA_OPEQ) == 1) {
|
||||
lua_pop(L, 1);
|
||||
return call_syntax::colon;
|
||||
|
@ -65,7 +65,7 @@ struct check_types {
|
||||
static bool check(types<Arg0, Args...>, std::index_sequence<I0, I...>, lua_State* L, int firstargument, Handler&& handler) {
|
||||
if (!stack::check<Arg0>(L, firstargument + I0, handler))
|
||||
return false;
|
||||
return check(types<Args...>(), std::index_sequence<I...>(), L, firstargument, std::forward<Handler>(handler));
|
||||
return check(types<Args...>(), std::index_sequence<I...>(), L, firstargument - static_cast<int>(std::is_same<this_state, meta::Unqualified<Arg0>>::value), std::forward<Handler>(handler));
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
@ -121,6 +121,22 @@ struct checker<nil_t, expected, C> {
|
||||
template <type expected, typename C>
|
||||
struct checker<nullopt_t, expected, C> : checker<nil_t> {};
|
||||
|
||||
template <typename C>
|
||||
struct checker<this_state, type::none, C> {
|
||||
template <typename Handler>
|
||||
static bool check (lua_State*, int, Handler&&) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
struct checker<variadic_args, type::poly, C> {
|
||||
template <typename Handler>
|
||||
static bool check (lua_State*, int, Handler&&) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename C>
|
||||
struct checker<T, type::poly, C> {
|
||||
template <typename Handler>
|
||||
|
@ -63,26 +63,12 @@ struct getter<T, std::enable_if_t<meta::And<std::is_integral<T>, std::is_unsigne
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
|
||||
struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> {
|
||||
static T get(lua_State* L, int index = -1) {
|
||||
return T(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T, std::enable_if_t<std::is_base_of<stack_reference, T>::value>> {
|
||||
static T get(lua_State* L, int index = -1) {
|
||||
return T(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<stack_reference> {
|
||||
static stack_reference get(lua_State* L, int index = -1) {
|
||||
return stack_reference(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<userdata_value> {
|
||||
static userdata_value get(lua_State* L, int index = -1) {
|
||||
@ -148,6 +134,13 @@ struct getter<nullopt_t> {
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<this_state> {
|
||||
static this_state get(lua_State* L, int = -1) {
|
||||
return this_state{L};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<lua_CFunction> {
|
||||
static lua_CFunction get(lua_State* L, int index = -1) {
|
||||
|
@ -39,9 +39,30 @@ public:
|
||||
return stack::get<T>(L, stack_index());
|
||||
}
|
||||
|
||||
int push () const {
|
||||
lua_pushvalue(L, index);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_State* lua_state() const { return L; }
|
||||
int stack_index() const { return index; }
|
||||
};
|
||||
|
||||
namespace stack {
|
||||
template <>
|
||||
struct getter<stack_proxy> {
|
||||
static stack_proxy get(lua_State* L, int index = -1) {
|
||||
return stack_proxy(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<stack_proxy> {
|
||||
static int push(lua_State*, const stack_proxy& ref) {
|
||||
return ref.push();
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
#endif // SOL_STACK_PROXY_HPP
|
||||
|
@ -175,7 +175,7 @@ struct pusher<T, std::enable_if_t<meta::And<meta::has_begin_end<T>, meta::has_ke
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct pusher<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
|
||||
struct pusher<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> {
|
||||
static int push(lua_State*, T& ref) {
|
||||
return ref.push();
|
||||
}
|
||||
@ -185,13 +185,6 @@ struct pusher<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<stack_reference> {
|
||||
static int push(lua_State*, const stack_reference& ref) {
|
||||
return ref.push();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<bool> {
|
||||
static int push(lua_State* L, bool b) {
|
||||
@ -333,6 +326,13 @@ struct pusher<nullopt_t> {
|
||||
return stack::push(L, nil);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct pusher<this_state> {
|
||||
static int push(lua_State*, const this_state&) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
|
@ -132,6 +132,17 @@ struct find_in_pack_v : Bool<false> { };
|
||||
template<typename V, typename Vs1, typename... Vs>
|
||||
struct find_in_pack_v<V, Vs1, Vs...> : Or<Bool<(V::value == Vs1::value)>, find_in_pack_v<V, Vs...>> { };
|
||||
|
||||
namespace meta_detail {
|
||||
template<std::size_t I, typename T, typename... Args>
|
||||
struct index_in_pack : std::integral_constant<std::ptrdiff_t, -1> { };
|
||||
|
||||
template<std::size_t I, typename T, typename T1, typename... Args>
|
||||
struct index_in_pack<I, T, T1, Args...> : std::conditional_t<std::is_same<T, T1>::value, std::integral_constant<std::ptrdiff_t, I>, index_in_pack<I + 1, T, Args...>> { };
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
struct index_in_pack : meta_detail::index_in_pack<0, T, Args...> { };
|
||||
|
||||
template<std::size_t I, typename... Args>
|
||||
struct at_in_pack {};
|
||||
|
||||
|
@ -83,7 +83,8 @@ inline int c_trampoline(lua_State* L, lua_CFunction f) {
|
||||
return trampoline(L, f);
|
||||
}
|
||||
#endif // Exceptions vs. No Exceptions
|
||||
}
|
||||
struct empty { void operator()() {} };
|
||||
} // detail
|
||||
struct nil_t {};
|
||||
const nil_t nil {};
|
||||
struct metatable_key_t {};
|
||||
@ -91,7 +92,7 @@ const metatable_key_t metatable_key = {};
|
||||
inline bool operator==(nil_t, nil_t) { return true; }
|
||||
inline bool operator!=(nil_t, nil_t) { return false; }
|
||||
|
||||
typedef std::add_lvalue_reference_t<std::remove_pointer_t<lua_CFunction>> lua_r_CFunction;
|
||||
typedef std::remove_pointer_t<lua_CFunction> lua_r_CFunction;
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct unique_usertype {};
|
||||
@ -132,6 +133,16 @@ struct c_closure {
|
||||
c_closure(lua_CFunction f, int upvalues = 0) : c_function(f), upvalues(upvalues) {}
|
||||
};
|
||||
|
||||
struct this_state {
|
||||
lua_State* L;
|
||||
operator lua_State* () const {
|
||||
return L;
|
||||
}
|
||||
lua_State* operator-> () const {
|
||||
return L;
|
||||
}
|
||||
};
|
||||
|
||||
enum class call_syntax {
|
||||
dot = 0,
|
||||
colon = 1
|
||||
@ -295,6 +306,7 @@ template <typename base_t>
|
||||
class basic_userdata;
|
||||
template <typename base_t>
|
||||
class basic_lightuserdata;
|
||||
struct variadic_args;
|
||||
using object = basic_object<reference>;
|
||||
using stack_object = basic_object<stack_reference>;
|
||||
using userdata = basic_userdata<reference>;
|
||||
@ -377,7 +389,10 @@ template <typename Signature>
|
||||
struct lua_type_of<std::function<Signature>> : std::integral_constant<type, type::function>{};
|
||||
|
||||
template <typename T>
|
||||
struct lua_type_of<optional<T>> : std::integral_constant<type, type::poly>{};
|
||||
struct lua_type_of<optional<T>> : std::integral_constant<type, type::poly> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<variadic_args> : std::integral_constant<type, type::poly> {};
|
||||
|
||||
template <typename T>
|
||||
struct lua_type_of<T*> : std::integral_constant<type, type::userdata> {};
|
||||
@ -388,6 +403,9 @@ struct lua_type_of<T, std::enable_if_t<std::is_arithmetic<T>::value>> : std::int
|
||||
template <typename T>
|
||||
struct lua_type_of<T, std::enable_if_t<std::is_enum<T>::value>> : std::integral_constant<type, type::number> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<this_state> : std::integral_constant<type, type::none> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_lua_primitive : std::integral_constant<bool,
|
||||
type::userdata != lua_type_of<meta::Unqualified<T>>::value
|
||||
|
@ -197,10 +197,15 @@ private:
|
||||
return std::make_unique<function_detail::usertype_constructor_function<T, Functions...>>(std::move(func.set));
|
||||
}
|
||||
|
||||
template<typename RSig, typename WSig>
|
||||
std::unique_ptr<function_detail::base_function> make_function(const std::string&, member_property<RSig, WSig> func) {
|
||||
return std::make_unique<function_detail::usertype_variable_function<T, member_property<RSig, WSig>>>(std::move(func));
|
||||
}
|
||||
|
||||
template<typename Fx>
|
||||
std::unique_ptr<function_detail::base_function> make_free_function(std::true_type, const std::string&, Fx&& func) {
|
||||
typedef std::decay_t<meta::Unqualified<Fx>> function_type;
|
||||
return std::make_unique<function_detail::usertype_function<function_type, T>>(func);
|
||||
return std::make_unique<function_detail::usertype_function<T, function_type>>(func);
|
||||
}
|
||||
|
||||
template<typename Fx>
|
||||
@ -219,16 +224,16 @@ private:
|
||||
|
||||
template<typename Base, typename Ret>
|
||||
std::unique_ptr<function_detail::base_function> make_variable_function(std::true_type, const std::string&, Ret Base::* func) {
|
||||
static_assert(std::is_base_of<Base, T>::value, "Any registered function must be part of the class");
|
||||
static_assert(std::is_base_of<Base, T>::value, "Any registered member variable must be part of the class");
|
||||
typedef std::decay_t<decltype(func)> function_type;
|
||||
return std::make_unique<function_detail::usertype_variable_function<function_type, T>>(func);
|
||||
return std::make_unique<function_detail::usertype_variable_function<T, function_type>>(func);
|
||||
}
|
||||
|
||||
template<typename Base, typename Ret>
|
||||
std::unique_ptr<function_detail::base_function> make_variable_function(std::false_type, const std::string&, Ret Base::* func) {
|
||||
static_assert(std::is_base_of<Base, T>::value, "Any registered function must be part of the class");
|
||||
static_assert(std::is_base_of<Base, T>::value, "Any registered member function must be part of the class");
|
||||
typedef std::decay_t<decltype(func)> function_type;
|
||||
return std::make_unique<function_detail::usertype_function<function_type, T>>(func);
|
||||
return std::make_unique<function_detail::usertype_function<T, function_type>>(func);
|
||||
}
|
||||
|
||||
template<typename Base, typename Ret>
|
||||
@ -240,7 +245,7 @@ private:
|
||||
template<typename Fx>
|
||||
std::unique_ptr<function_detail::base_function> make_functor_function(std::true_type, const std::string&, Fx&& func) {
|
||||
typedef std::decay_t<meta::Unqualified<Fx>> function_type;
|
||||
return std::make_unique<function_detail::usertype_function<function_type, T>>(func);
|
||||
return std::make_unique<function_detail::usertype_function<T, function_type>>(func);
|
||||
}
|
||||
|
||||
template<typename Fx>
|
||||
@ -339,7 +344,7 @@ private:
|
||||
|
||||
template<std::size_t N, typename Fx>
|
||||
void build_function(std::string funcname, Fx&& func) {
|
||||
typedef std::is_member_object_pointer<meta::Unqualified<Fx>> is_variable;
|
||||
typedef meta::Or<std::is_member_object_pointer<meta::Unqualified<Fx>>, meta::is_specialization_of<member_property, meta::Unqualified<Fx>>> is_variable;
|
||||
functionnames.push_back(std::move(funcname));
|
||||
std::string& name = functionnames.back();
|
||||
auto baseptr = make_function(name, std::forward<Fx>(func));
|
||||
|
102
sol/variadic_args.hpp
Normal file
102
sol/variadic_args.hpp
Normal file
@ -0,0 +1,102 @@
|
||||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef SOL_VARIADIC_ARGS_HPP
|
||||
#define SOL_VARIADIC_ARGS_HPP
|
||||
|
||||
#include "stack.hpp"
|
||||
#include "stack_proxy.hpp"
|
||||
|
||||
namespace sol {
|
||||
struct variadic_args {
|
||||
private:
|
||||
lua_State* L;
|
||||
int index;
|
||||
int stacktop;
|
||||
|
||||
public:
|
||||
variadic_args() = default;
|
||||
variadic_args(lua_State* L, int index = -1): L(L), index(lua_absindex(L, index)), stacktop(lua_gettop(L)) {}
|
||||
variadic_args(const variadic_args&) = default;
|
||||
variadic_args& operator=(const variadic_args&) = default;
|
||||
variadic_args(variadic_args&& o) : L(o.L), index(o.index), stacktop(o.stacktop) {
|
||||
// Must be manual, otherwise destructor will screw us
|
||||
// return count being 0 is enough to keep things clean
|
||||
// but will be thorough
|
||||
o.L = nullptr;
|
||||
o.index = 0;
|
||||
o.stacktop = 0;
|
||||
}
|
||||
variadic_args& operator=(variadic_args&& o) {
|
||||
L = o.L;
|
||||
index = o.index;
|
||||
stacktop = o.stacktop;
|
||||
// Must be manual, otherwise destructor will screw us
|
||||
// return count being 0 is enough to keep things clean
|
||||
// but will be thorough
|
||||
o.L = nullptr;
|
||||
o.index = 0;
|
||||
o.stacktop = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int push () const {
|
||||
int pushcount = 0;
|
||||
for (int i = index; i <= stacktop; ++i) {
|
||||
lua_pushvalue(L, i);
|
||||
pushcount += 1;
|
||||
}
|
||||
return pushcount;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
decltype(auto) get(int start = 0) const {
|
||||
return stack::get<T>(L, index + start);
|
||||
}
|
||||
|
||||
stack_proxy operator[](int start) const {
|
||||
return stack_proxy(L, index + start);
|
||||
}
|
||||
|
||||
lua_State* lua_state() const { return L; };
|
||||
int stack_index() const { return index; };
|
||||
int leftover_count() const { return stacktop - (index - 1); }
|
||||
int top() const { return stacktop; }
|
||||
};
|
||||
|
||||
namespace stack {
|
||||
template <>
|
||||
struct getter<variadic_args> {
|
||||
static variadic_args get(lua_State* L, int index = -1) {
|
||||
return variadic_args(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<variadic_args> {
|
||||
static int push(lua_State*, const variadic_args& ref) {
|
||||
return ref.push();
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
#endif // SOL_VARIADIC_ARGS_HPP
|
@ -749,3 +749,35 @@ end)");
|
||||
REQUIRE(b == 2);
|
||||
REQUIRE(c == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("functions/variadic_args", "Check to see we can receive multiple arguments through a variadic") {
|
||||
struct structure {
|
||||
int x;
|
||||
bool b;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.set_function("v", [](sol::this_state, sol::variadic_args va) -> structure {
|
||||
int r = 0;
|
||||
for (int i = 0; i < va.leftover_count(); ++i) {
|
||||
int v = va[i];
|
||||
r += v;
|
||||
}
|
||||
return{ r, r > 200 };
|
||||
});
|
||||
|
||||
lua.script("x = v(25, 25)");
|
||||
lua.script("x2 = v(25, 25, 100, 50, 250, 150)");
|
||||
lua.script("x3 = v(1, 2, 3, 4, 5, 6)");
|
||||
|
||||
structure& lx = lua["x"];
|
||||
structure& lx2 = lua["x2"];
|
||||
structure& lx3 = lua["x3"];
|
||||
REQUIRE(lx.x == 50);
|
||||
REQUIRE(lx2.x == 600);
|
||||
REQUIRE(lx3.x == 21);
|
||||
REQUIRE_FALSE(lx.b);
|
||||
REQUIRE(lx2.b);
|
||||
REQUIRE_FALSE(lx3.b);
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
struct stack_guard {
|
||||
struct test_stack_guard {
|
||||
lua_State* L;
|
||||
int& begintop;
|
||||
int& endtop;
|
||||
stack_guard(lua_State* L, int& begintop, int& endtop) : L(L), begintop(begintop), endtop(endtop) {
|
||||
test_stack_guard(lua_State* L, int& begintop, int& endtop) : L(L), begintop(begintop), endtop(endtop) {
|
||||
begintop = lua_gettop(L);
|
||||
}
|
||||
~stack_guard() { endtop = lua_gettop(L); }
|
||||
~test_stack_guard() { endtop = lua_gettop(L); }
|
||||
};
|
||||
|
@ -168,7 +168,7 @@ TEST_CASE("tables/iterators", "Testing the use of iteratrs to get values from a
|
||||
int begintop = 0;
|
||||
int endtop = 0;
|
||||
{
|
||||
stack_guard s(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard s(lua.lua_state(), begintop, endtop);
|
||||
for (auto& kvp : tbl) {
|
||||
[&iterations](sol::object key, sol::object value) {
|
||||
++iterations;
|
||||
|
112
tests.cpp
112
tests.cpp
@ -192,39 +192,39 @@ TEST_CASE("table/traversal", "ensure that we can chain requests and tunnel down
|
||||
|
||||
lua.script("t1 = {t2 = {t3 = 24}};");
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
int traversex24 = lua.traverse_get<int>("t1", "t2", "t3");
|
||||
REQUIRE(traversex24 == 24);
|
||||
} REQUIRE(begintop == endtop);
|
||||
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
int x24 = lua["t1"]["t2"]["t3"];
|
||||
REQUIRE(x24 == 24);
|
||||
} REQUIRE(begintop == endtop);
|
||||
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
lua["t1"]["t2"]["t3"] = 64;
|
||||
int traversex64 = lua.traverse_get<int>("t1", "t2", "t3");
|
||||
REQUIRE(traversex64 == 64);
|
||||
} REQUIRE(begintop == endtop);
|
||||
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
int x64 = lua["t1"]["t2"]["t3"];
|
||||
REQUIRE(x64 == 64);
|
||||
} REQUIRE(begintop == endtop);
|
||||
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
lua.traverse_set("t1", "t2", "t3", 13);
|
||||
int traversex13 = lua.traverse_get<int>("t1", "t2", "t3");
|
||||
REQUIRE(traversex13 == 13);
|
||||
} REQUIRE(begintop == endtop);
|
||||
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
int x13 = lua["t1"]["t2"]["t3"];
|
||||
REQUIRE(x13 == 13);
|
||||
} REQUIRE(begintop == endtop);
|
||||
@ -234,18 +234,18 @@ TEST_CASE("simple/set", "Check if the set works properly.") {
|
||||
sol::state lua;
|
||||
int begintop = 0, endtop = 0;
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
lua.set("a", 9);
|
||||
} REQUIRE(begintop == endtop);
|
||||
REQUIRE_NOTHROW(lua.script("if a ~= 9 then error('wrong value') end"));
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
lua.set("d", "hello");
|
||||
} REQUIRE(begintop == endtop);
|
||||
REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
|
||||
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
lua.set("e", std::string("hello"), "f", true);
|
||||
} REQUIRE(begintop == endtop);
|
||||
REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
|
||||
@ -258,21 +258,21 @@ TEST_CASE("simple/get", "Tests if the get function works properly.") {
|
||||
|
||||
lua.script("a = 9");
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
auto a = lua.get<int>("a");
|
||||
REQUIRE(a == 9.0);
|
||||
} REQUIRE(begintop == endtop);
|
||||
|
||||
lua.script("b = nil");
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
REQUIRE_NOTHROW(lua.get<sol::nil_t>("b"));
|
||||
} REQUIRE(begintop == endtop);
|
||||
|
||||
lua.script("d = 'hello'");
|
||||
lua.script("e = true");
|
||||
{
|
||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||
std::string d;
|
||||
bool e;
|
||||
std::tie( d, e ) = lua.get<std::string, bool>("d", "e");
|
||||
@ -944,3 +944,91 @@ lw2 = bark.something2(2, 3)
|
||||
|
||||
REQUIRE_THROWS(lua.script("b.var2 = 2"));
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/properties", "Check if member properties/variables work") {
|
||||
struct bark {
|
||||
int var = 50;
|
||||
int var2 = 25;
|
||||
|
||||
int get_var2() const {
|
||||
return var2;
|
||||
}
|
||||
|
||||
int get_var3() {
|
||||
return var2;
|
||||
}
|
||||
|
||||
void set_var2( int x ) {
|
||||
var2 = x;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_usertype<bark>("bark",
|
||||
"var", &bark::var,
|
||||
"var2", sol::readonly( &bark::var2 ),
|
||||
"a", sol::property(&bark::get_var2, &bark::set_var2),
|
||||
"b", sol::property(&bark::get_var2),
|
||||
"c", sol::property(&bark::get_var3),
|
||||
"d", sol::property(&bark::set_var2)
|
||||
);
|
||||
|
||||
bark b;
|
||||
lua.set("b", &b);
|
||||
|
||||
lua.script("b.a = 59");
|
||||
lua.script("var2_0 = b.a");
|
||||
lua.script("var2_1 = b.b");
|
||||
lua.script("b.d = 1568");
|
||||
lua.script("var2_2 = b.c");
|
||||
|
||||
int var2_0 = lua["var2_0"];
|
||||
int var2_1 = lua["var2_1"];
|
||||
int var2_2 = lua["var2_2"];
|
||||
REQUIRE(var2_0 == 59);
|
||||
REQUIRE(var2_1 == 59);
|
||||
REQUIRE(var2_2 == 1568);
|
||||
|
||||
REQUIRE_THROWS(lua.script("b.var2 = 24"));
|
||||
REQUIRE_THROWS(lua.script("r = b.d"));
|
||||
REQUIRE_THROWS(lua.script("r = b.d"));
|
||||
REQUIRE_THROWS(lua.script("b.b = 25"));
|
||||
REQUIRE_THROWS(lua.script("b.c = 11"));
|
||||
}
|
||||
|
||||
TEST_CASE("utilities/this_state", "Ensure this_state argument can be gotten anywhere in the function.") {
|
||||
struct bark {
|
||||
int with_state(sol::this_state l, int a, int b) {
|
||||
lua_State* L = l;
|
||||
int c = lua_gettop(L);
|
||||
return a + b + (c - c);
|
||||
}
|
||||
|
||||
static int with_state_2(int a, sol::this_state l, int b) {
|
||||
lua_State* L = l;
|
||||
int c = lua_gettop(L);
|
||||
return a * b + (c - c);
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.new_usertype<bark>("bark",
|
||||
"with_state", &bark::with_state
|
||||
);
|
||||
|
||||
bark b;
|
||||
lua.set("b", &b);
|
||||
lua.set("with_state_2", bark::with_state_2);
|
||||
sol::function fx = lua["with_state_2"];
|
||||
int a = fx(25, 25);
|
||||
lua.script("a = with_state_2(25, 25)");
|
||||
lua.script("c = b:with_state(25, 25)");
|
||||
int la = lua["a"];
|
||||
int lc = lua["c"];
|
||||
|
||||
REQUIRE(lc == 50);
|
||||
REQUIRE(a == 625);
|
||||
REQUIRE(la == 625);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user