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"
|
#include "resolve.hpp"
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
|
|
||||||
template <typename Sig, typename... Ps>
|
template <typename Sig, typename... Ps>
|
||||||
struct function_arguments {
|
struct function_arguments {
|
||||||
std::tuple<Ps...> params;
|
std::tuple<Ps...> params;
|
||||||
|
@ -80,7 +80,7 @@ struct upvalue_member_function {
|
|||||||
template <int N, typename R, typename M, typename V>
|
template <int N, typename R, typename M, typename V>
|
||||||
int set_assignable(std::false_type, lua_State* L, M&, V&) {
|
int set_assignable(std::false_type, lua_State* L, M&, V&) {
|
||||||
lua_pop(L, N);
|
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>
|
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>
|
template <int N, typename R, typename M, typename V>
|
||||||
int set_variable(std::false_type, lua_State* L, M&, V&) {
|
int set_variable(std::false_type, lua_State* L, M&, V&) {
|
||||||
lua_pop(L, N);
|
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>
|
template<typename T, typename Function>
|
||||||
|
@ -26,6 +26,108 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace sol {
|
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 {
|
namespace function_detail {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct implicit_wrapper {
|
struct implicit_wrapper {
|
||||||
@ -48,35 +150,62 @@ inline decltype(auto) cleanup_key() {
|
|||||||
template<typename T, typename Func, typename = void>
|
template<typename T, typename Func, typename = void>
|
||||||
struct functor {
|
struct functor {
|
||||||
typedef meta::bind_traits<Func> traits_type;
|
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;
|
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;
|
T* item;
|
||||||
Func invocation;
|
function_type invocation;
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
bool check () const {
|
|
||||||
return invocation != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void call(types<void>, Args&&... args) {
|
void call(types<void>, Args&&... args) {
|
||||||
T& member = *item;
|
T& member = *item;
|
||||||
(member.*invocation)(std::forward<Args>(args)...);
|
invocation(implicit_wrapper<T>(member), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Ret, typename... Args>
|
template<typename Ret, typename... Args>
|
||||||
Ret call(types<Ret>, Args&&... args) {
|
Ret call(types<Ret>, Args&&... args) {
|
||||||
T& member = *item;
|
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>
|
template<typename... Args>
|
||||||
decltype(auto) operator()(Args&&... 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::args_type args_type;
|
||||||
typedef typename traits_type::return_type return_type;
|
typedef typename traits_type::return_type return_type;
|
||||||
static const std::size_t arity = traits_type::arity;
|
static const std::size_t arity = traits_type::arity;
|
||||||
|
typedef std::true_type can_read;
|
||||||
|
typedef std::true_type can_write;
|
||||||
|
|
||||||
T* item;
|
T* item;
|
||||||
Func invocation;
|
Func invocation;
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
bool check () const {
|
|
||||||
return this->fx.invocation != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Arg>
|
template<typename Arg>
|
||||||
void call(Arg&& arg) {
|
void call(Arg&& arg) {
|
||||||
T& member = *item;
|
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>
|
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::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;
|
typedef typename traits_type::return_type return_type;
|
||||||
static const std::size_t arity = traits_type::arity;
|
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;
|
T* item;
|
||||||
function_type invocation;
|
Func invocation;
|
||||||
|
|
||||||
private:
|
|
||||||
bool check(std::false_type) const {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool check(std::true_type) const {
|
|
||||||
return this->invocation != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
functor(Args&&... args): item(nullptr), invocation(std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
bool check () const {
|
|
||||||
return this->check(std::is_function<Func>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void call(types<void>, Args&&... args) {
|
void call(types<void>, Args&&... args) {
|
||||||
T& member = *item;
|
T& member = *item;
|
||||||
invocation(implicit_wrapper<T>(member), std::forward<Args>(args)...);
|
(member.*invocation)(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Ret, typename... Args>
|
template<typename Ret, typename... Args>
|
||||||
Ret call(types<Ret>, Args&&... args) {
|
Ret call(types<Ret>, Args&&... args) {
|
||||||
T& member = *item;
|
T& member = *item;
|
||||||
return invocation(implicit_wrapper<T>(member), std::forward<Args>(args)...);
|
return (member.*invocation)(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
auto operator()(Args&&... args) -> decltype(std::declval<functor>().call(types<return_type>{}, std::forward<Args>(args)...)) {
|
decltype(auto) operator()(Args&&... args) {
|
||||||
return this->call(types<return_type>(), std::forward<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) {
|
int set_assignable(std::false_type, lua_State* L, M) {
|
||||||
lua_pop(L, 1);
|
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) {
|
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) {
|
int set_variable(std::false_type, lua_State* L, M) {
|
||||||
lua_pop(L, 1);
|
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) {
|
int call(lua_State* L) {
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace function_detail {
|
namespace function_detail {
|
||||||
template<typename Function, typename Tp>
|
template<typename Tp, typename Function>
|
||||||
struct usertype_function_core : public base_function {
|
struct usertype_function_core : public base_function {
|
||||||
typedef std::remove_pointer_t<Tp> T;
|
typedef std::remove_pointer_t<Tp> T;
|
||||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
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>
|
template<typename... Args>
|
||||||
usertype_function_core(Args&&... args): fx(std::forward<Args>(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>
|
template<typename... Ret, typename... Args, std::size_t Start>
|
||||||
int operator()(types<Ret...> tr, types<Args...> ta, index_value<Start>, lua_State* L) {
|
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);
|
return stack::call_into_lua<1>(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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Function, typename Tp>
|
template<typename Tp, typename Function>
|
||||||
struct usertype_function : public usertype_function_core<Function, Tp> {
|
struct usertype_function : public usertype_function_core<Tp, Function> {
|
||||||
typedef usertype_function_core<Function, Tp> base_t;
|
typedef usertype_function_core<Tp, Function> base_t;
|
||||||
typedef std::remove_pointer_t<Tp> T;
|
typedef std::remove_pointer_t<Tp> T;
|
||||||
typedef typename base_t::traits_type traits_type;
|
typedef typename base_t::traits_type traits_type;
|
||||||
typedef typename base_t::args_type args_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>
|
template<typename Tp, typename Function>
|
||||||
struct usertype_variable_function : public usertype_function_core<Function, Tp> {
|
struct usertype_variable_function : public usertype_function_core<Tp, Function> {
|
||||||
typedef usertype_function_core<Function, Tp> base_t;
|
typedef usertype_function_core<Tp, Function> base_t;
|
||||||
typedef std::remove_pointer_t<Tp> 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::traits_type traits_type;
|
||||||
typedef typename base_t::args_type args_type;
|
typedef typename base_t::args_type args_type;
|
||||||
typedef typename base_t::return_type return_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>
|
template<typename... Args>
|
||||||
usertype_variable_function(Args&&... args): base_t(std::forward<Args>(args)...) {}
|
usertype_variable_function(Args&&... args): base_t(std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
int set_assignable(std::false_type, lua_State* L) {
|
int set_assignable(std::false_type, lua_State* L) {
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 3);
|
||||||
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) {
|
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);
|
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) {
|
int set_variable(std::false_type, lua_State* L) {
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 3);
|
||||||
return luaL_error(L, "cannot write to a const variable");
|
return luaL_error(L, "sol: cannot write to a const variable");
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_variable(std::true_type, lua_State* L) {
|
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);
|
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 prelude(lua_State* L) {
|
||||||
int argcount = lua_gettop(L);
|
int argcount = lua_gettop(L);
|
||||||
this->fx.item = stack::get<T*>(L, 1);
|
this->fx.item = stack::get<T*>(L, 1);
|
||||||
switch(argcount) {
|
switch(argcount) {
|
||||||
case 2:
|
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:
|
case 3:
|
||||||
return set_variable(meta::Not<std::is_const<return_type>>(), L);
|
return set_variable(meta::Not<std::is_const<return_type>>(), L);
|
||||||
default:
|
default:
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "reference.hpp"
|
#include "reference.hpp"
|
||||||
#include "userdata.hpp"
|
#include "userdata.hpp"
|
||||||
#include "stack.hpp"
|
#include "stack.hpp"
|
||||||
|
#include "variadic_args.hpp"
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
template <typename base_t>
|
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>>
|
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) {
|
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);
|
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>
|
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) {
|
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);
|
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
|
} // 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>>
|
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) {
|
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)...);
|
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>
|
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) {
|
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)...);
|
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)...);
|
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;
|
int nargs = static_cast<int>(sizeof...(Args)) + additionalpop;
|
||||||
lua_pop(L, nargs);
|
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) {
|
inline call_syntax get_call_syntax(lua_State* L, const std::string& key) {
|
||||||
luaL_getmetatable(L, meta.c_str());
|
luaL_getmetatable(L, key.c_str());
|
||||||
if (lua_compare(L, -1, -2, LUA_OPEQ) == 1) {
|
if (lua_compare(L, -1, -2, LUA_OPEQ) == 1) {
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
return call_syntax::colon;
|
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) {
|
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))
|
if (!stack::check<Arg0>(L, firstargument + I0, handler))
|
||||||
return false;
|
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>
|
template <typename Handler>
|
||||||
@ -121,6 +121,22 @@ struct checker<nil_t, expected, C> {
|
|||||||
template <type expected, typename C>
|
template <type expected, typename C>
|
||||||
struct checker<nullopt_t, expected, C> : checker<nil_t> {};
|
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>
|
template <typename T, typename C>
|
||||||
struct checker<T, type::poly, C> {
|
struct checker<T, type::poly, C> {
|
||||||
template <typename Handler>
|
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>
|
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) {
|
static T get(lua_State* L, int index = -1) {
|
||||||
return T(L, index);
|
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<>
|
template<>
|
||||||
struct getter<userdata_value> {
|
struct getter<userdata_value> {
|
||||||
static userdata_value get(lua_State* L, int index = -1) {
|
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<>
|
template<>
|
||||||
struct getter<lua_CFunction> {
|
struct getter<lua_CFunction> {
|
||||||
static lua_CFunction get(lua_State* L, int index = -1) {
|
static lua_CFunction get(lua_State* L, int index = -1) {
|
||||||
|
@ -39,9 +39,30 @@ public:
|
|||||||
return stack::get<T>(L, stack_index());
|
return stack::get<T>(L, stack_index());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int push () const {
|
||||||
|
lua_pushvalue(L, index);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
lua_State* lua_state() const { return L; }
|
lua_State* lua_state() const { return L; }
|
||||||
int stack_index() const { return index; }
|
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
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_STACK_PROXY_HPP
|
#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>
|
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) {
|
static int push(lua_State*, T& ref) {
|
||||||
return ref.push();
|
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<>
|
template<>
|
||||||
struct pusher<bool> {
|
struct pusher<bool> {
|
||||||
static int push(lua_State* L, bool b) {
|
static int push(lua_State* L, bool b) {
|
||||||
@ -333,6 +326,13 @@ struct pusher<nullopt_t> {
|
|||||||
return stack::push(L, nil);
|
return stack::push(L, nil);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct pusher<this_state> {
|
||||||
|
static int push(lua_State*, const this_state&) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
} // stack
|
} // stack
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
|
@ -132,6 +132,17 @@ struct find_in_pack_v : Bool<false> { };
|
|||||||
template<typename V, typename Vs1, typename... Vs>
|
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...>> { };
|
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>
|
template<std::size_t I, typename... Args>
|
||||||
struct at_in_pack {};
|
struct at_in_pack {};
|
||||||
|
|
||||||
|
@ -83,7 +83,8 @@ inline int c_trampoline(lua_State* L, lua_CFunction f) {
|
|||||||
return trampoline(L, f);
|
return trampoline(L, f);
|
||||||
}
|
}
|
||||||
#endif // Exceptions vs. No Exceptions
|
#endif // Exceptions vs. No Exceptions
|
||||||
}
|
struct empty { void operator()() {} };
|
||||||
|
} // detail
|
||||||
struct nil_t {};
|
struct nil_t {};
|
||||||
const nil_t nil {};
|
const nil_t nil {};
|
||||||
struct metatable_key_t {};
|
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 true; }
|
||||||
inline bool operator!=(nil_t, nil_t) { return false; }
|
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>
|
template <typename T, typename = void>
|
||||||
struct unique_usertype {};
|
struct unique_usertype {};
|
||||||
@ -132,6 +133,16 @@ struct c_closure {
|
|||||||
c_closure(lua_CFunction f, int upvalues = 0) : c_function(f), upvalues(upvalues) {}
|
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 {
|
enum class call_syntax {
|
||||||
dot = 0,
|
dot = 0,
|
||||||
colon = 1
|
colon = 1
|
||||||
@ -295,6 +306,7 @@ template <typename base_t>
|
|||||||
class basic_userdata;
|
class basic_userdata;
|
||||||
template <typename base_t>
|
template <typename base_t>
|
||||||
class basic_lightuserdata;
|
class basic_lightuserdata;
|
||||||
|
struct variadic_args;
|
||||||
using object = basic_object<reference>;
|
using object = basic_object<reference>;
|
||||||
using stack_object = basic_object<stack_reference>;
|
using stack_object = basic_object<stack_reference>;
|
||||||
using userdata = basic_userdata<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>{};
|
struct lua_type_of<std::function<Signature>> : std::integral_constant<type, type::function>{};
|
||||||
|
|
||||||
template <typename T>
|
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>
|
template <typename T>
|
||||||
struct lua_type_of<T*> : std::integral_constant<type, type::userdata> {};
|
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>
|
template <typename T>
|
||||||
struct lua_type_of<T, std::enable_if_t<std::is_enum<T>::value>> : std::integral_constant<type, type::number> {};
|
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>
|
template <typename T>
|
||||||
struct is_lua_primitive : std::integral_constant<bool,
|
struct is_lua_primitive : std::integral_constant<bool,
|
||||||
type::userdata != lua_type_of<meta::Unqualified<T>>::value
|
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));
|
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>
|
template<typename Fx>
|
||||||
std::unique_ptr<function_detail::base_function> make_free_function(std::true_type, const std::string&, Fx&& func) {
|
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;
|
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>
|
template<typename Fx>
|
||||||
@ -219,16 +224,16 @@ private:
|
|||||||
|
|
||||||
template<typename Base, typename Ret>
|
template<typename Base, typename Ret>
|
||||||
std::unique_ptr<function_detail::base_function> make_variable_function(std::true_type, const std::string&, Ret Base::* func) {
|
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;
|
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>
|
template<typename Base, typename Ret>
|
||||||
std::unique_ptr<function_detail::base_function> make_variable_function(std::false_type, const std::string&, Ret Base::* func) {
|
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;
|
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>
|
template<typename Base, typename Ret>
|
||||||
@ -240,7 +245,7 @@ private:
|
|||||||
template<typename Fx>
|
template<typename Fx>
|
||||||
std::unique_ptr<function_detail::base_function> make_functor_function(std::true_type, const std::string&, Fx&& func) {
|
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;
|
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>
|
template<typename Fx>
|
||||||
@ -339,7 +344,7 @@ private:
|
|||||||
|
|
||||||
template<std::size_t N, typename Fx>
|
template<std::size_t N, typename Fx>
|
||||||
void build_function(std::string funcname, Fx&& func) {
|
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));
|
functionnames.push_back(std::move(funcname));
|
||||||
std::string& name = functionnames.back();
|
std::string& name = functionnames.back();
|
||||||
auto baseptr = make_function(name, std::forward<Fx>(func));
|
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
|
@ -443,11 +443,11 @@ TEST_CASE("functions/all-kinds", "Register all kinds of functions, make sure the
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct inner {
|
struct inner {
|
||||||
const int z = 5653;
|
const int z = 5653;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nested {
|
struct nested {
|
||||||
inner i;
|
inner i;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto a = []() { return 500; };
|
auto a = []() { return 500; };
|
||||||
@ -749,3 +749,35 @@ end)");
|
|||||||
REQUIRE(b == 2);
|
REQUIRE(b == 2);
|
||||||
REQUIRE(c == 3);
|
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
|
#pragma once
|
||||||
|
|
||||||
struct stack_guard {
|
struct test_stack_guard {
|
||||||
lua_State* L;
|
lua_State* L;
|
||||||
int& begintop;
|
int& begintop;
|
||||||
int& endtop;
|
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);
|
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 begintop = 0;
|
||||||
int endtop = 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) {
|
for (auto& kvp : tbl) {
|
||||||
[&iterations](sol::object key, sol::object value) {
|
[&iterations](sol::object key, sol::object value) {
|
||||||
++iterations;
|
++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}};");
|
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");
|
int traversex24 = lua.traverse_get<int>("t1", "t2", "t3");
|
||||||
REQUIRE(traversex24 == 24);
|
REQUIRE(traversex24 == 24);
|
||||||
} REQUIRE(begintop == endtop);
|
} 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"];
|
int x24 = lua["t1"]["t2"]["t3"];
|
||||||
REQUIRE(x24 == 24);
|
REQUIRE(x24 == 24);
|
||||||
} REQUIRE(begintop == endtop);
|
} 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;
|
lua["t1"]["t2"]["t3"] = 64;
|
||||||
int traversex64 = lua.traverse_get<int>("t1", "t2", "t3");
|
int traversex64 = lua.traverse_get<int>("t1", "t2", "t3");
|
||||||
REQUIRE(traversex64 == 64);
|
REQUIRE(traversex64 == 64);
|
||||||
} REQUIRE(begintop == endtop);
|
} 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"];
|
int x64 = lua["t1"]["t2"]["t3"];
|
||||||
REQUIRE(x64 == 64);
|
REQUIRE(x64 == 64);
|
||||||
} REQUIRE(begintop == endtop);
|
} 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);
|
lua.traverse_set("t1", "t2", "t3", 13);
|
||||||
int traversex13 = lua.traverse_get<int>("t1", "t2", "t3");
|
int traversex13 = lua.traverse_get<int>("t1", "t2", "t3");
|
||||||
REQUIRE(traversex13 == 13);
|
REQUIRE(traversex13 == 13);
|
||||||
} REQUIRE(begintop == endtop);
|
} 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"];
|
int x13 = lua["t1"]["t2"]["t3"];
|
||||||
REQUIRE(x13 == 13);
|
REQUIRE(x13 == 13);
|
||||||
} REQUIRE(begintop == endtop);
|
} REQUIRE(begintop == endtop);
|
||||||
@ -234,18 +234,18 @@ TEST_CASE("simple/set", "Check if the set works properly.") {
|
|||||||
sol::state lua;
|
sol::state lua;
|
||||||
int begintop = 0, endtop = 0;
|
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);
|
lua.set("a", 9);
|
||||||
} REQUIRE(begintop == endtop);
|
} REQUIRE(begintop == endtop);
|
||||||
REQUIRE_NOTHROW(lua.script("if a ~= 9 then error('wrong value') end"));
|
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");
|
lua.set("d", "hello");
|
||||||
} REQUIRE(begintop == endtop);
|
} REQUIRE(begintop == endtop);
|
||||||
REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
|
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);
|
lua.set("e", std::string("hello"), "f", true);
|
||||||
} REQUIRE(begintop == endtop);
|
} REQUIRE(begintop == endtop);
|
||||||
REQUIRE_NOTHROW(lua.script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
|
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");
|
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");
|
auto a = lua.get<int>("a");
|
||||||
REQUIRE(a == 9.0);
|
REQUIRE(a == 9.0);
|
||||||
} REQUIRE(begintop == endtop);
|
} REQUIRE(begintop == endtop);
|
||||||
|
|
||||||
lua.script("b = nil");
|
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_NOTHROW(lua.get<sol::nil_t>("b"));
|
||||||
} REQUIRE(begintop == endtop);
|
} REQUIRE(begintop == endtop);
|
||||||
|
|
||||||
lua.script("d = 'hello'");
|
lua.script("d = 'hello'");
|
||||||
lua.script("e = true");
|
lua.script("e = true");
|
||||||
{
|
{
|
||||||
stack_guard g(lua.lua_state(), begintop, endtop);
|
test_stack_guard g(lua.lua_state(), begintop, endtop);
|
||||||
std::string d;
|
std::string d;
|
||||||
bool e;
|
bool e;
|
||||||
std::tie( d, e ) = lua.get<std::string, bool>("d", "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"));
|
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