sol::var is now in business

This commit is contained in:
ThePhD 2016-08-06 17:29:07 -04:00
parent 0dcc879ce6
commit dc05552e81
7 changed files with 109 additions and 6 deletions

View File

@ -11,4 +11,5 @@ This type is no different from :doc:`regular usertype<usertype>`, but with the f
- :doc:`properties<property>` also become functions, similar to how member variables are treated above
* Automatic "__index" and "__newindex" handling is not done
- Overriding either of these properties leaves it entirely up to you to handle how you find variables
- This includes ``sol::var( ... )``, and similar "dot-access" types
- If you override "__index" or "__newindex", you must perform a raw get on the original table and return a valid function / value if you want it to find the members you already set on the ``simple_usertype``

View File

@ -226,6 +226,10 @@ Then, to register the base classes explicitly:
sol::base_classes, sol::bases<A>()
);
.. note::
You must list ALL base classes, including (if there were any) the base classes of A, and the base classes of those base classes, etc. if you want Sol/Lua to handle them automagically.
.. note::
Sol does not support down-casting from a base class to a derived class at runtime.

View File

@ -170,6 +170,20 @@ namespace sol {
}
};
template <typename T, bool is_index, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<var_wrapper<T>, is_index, is_variable, checked, boost, C> {
template <typename F>
static int call(lua_State* L, F&& f) {
if (is_index) {
return stack::push(L, detail::unwrap(f.value));
}
else {
detail::unwrap(f.value) = stack::get<meta::unwrapped_t<T>>(L, 3 + boost);
return 0;
}
}
};
template <bool is_index, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, checked, boost, C> {
static int call(lua_State* L, lua_r_CFunction f) {
@ -468,6 +482,8 @@ namespace sol {
template <typename R, typename W>
struct is_var_bind<property_wrapper<R, W>> : std::true_type {};
template <typename T>
struct is_var_bind<var_wrapper<T>> : std::true_type {};
} // call_detail
template <typename T>

View File

@ -196,9 +196,12 @@ namespace sol {
return stack::push<T>(L, detail::forward_get<I>(fp.params)...);
}
template <typename FP>
static int push(lua_State* L, FP&& fp) {
return push_func(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<FP>(fp));
static int push(lua_State* L, const function_arguments<T, Args...>& fp) {
return push_func(std::make_index_sequence<sizeof...(Args)>(), L, fp);
}
static int push(lua_State* L, function_arguments<T, Args...>&& fp) {
return push_func(std::make_index_sequence<sizeof...(Args)>(), L, std::move(fp));
}
};

View File

@ -75,11 +75,28 @@ namespace sol {
// Allow someone to make a member variable readonly (const)
template <typename R, typename T>
auto readonly(R T::* v) {
inline auto readonly(R T::* v) {
typedef const R C;
return static_cast<C T::*>(v);
}
template <typename T>
struct var_wrapper {
T value;
template <typename... Args>
var_wrapper(Args&&... args) : value(std::forward<Args>(args)...) {}
var_wrapper(const var_wrapper&) = default;
var_wrapper(var_wrapper&&) = default;
var_wrapper& operator=(const var_wrapper&) = default;
var_wrapper& operator=(var_wrapper&&) = default;
};
template <typename V>
inline auto var(V&& v) {
typedef meta::unqualified_t<V> T;
return var_wrapper<T>(std::forward<V>(v));
}
} // sol
#endif // SOL_PROPERTY_HPP

View File

@ -197,6 +197,9 @@ namespace sol {
template <std::size_t Idx, typename N, typename F, typename = std::enable_if_t<!meta::any_same<meta::unqualified_t<N>, base_classes_tag, call_construction>::value>>
void make_regs(regs_t& l, int& index, N&& n, F&&) {
if (is_variable_binding<meta::unqualified_t<F>>::value) {
return;
}
luaL_Reg reg = usertype_detail::make_reg(std::forward<N>(n), make_func<Idx>());
// Returnable scope
// That would be a neat keyword for C++
@ -223,7 +226,7 @@ namespace sol {
usertype_metatable(Args&&... args) : functions(std::forward<Args>(args)...),
indexfunc(usertype_detail::indexing_fail<true>), newindexfunc(usertype_detail::indexing_fail<false>),
destructfunc(nullptr), callconstructfunc(nullptr), baseclasscheck(nullptr), baseclasscast(nullptr),
mustindex(contains_variable() || contains_index()), secondarymeta(false) {
mustindex(contains_variable() || contains_index()), secondarymeta(contains_variable()) {
}
template <std::size_t I0, std::size_t I1, bool is_index>
@ -400,7 +403,11 @@ namespace sol {
lua_createtable(L, 0, 1);
stack_reference metabehind(L, -1);
if (um.callconstructfunc != nullptr) {
stack::set_field(L, sol::meta_function::call_function, make_closure(um.callconstructfunc, make_light(um)), metabehind.stack_index());
stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um)), metabehind.stack_index());
}
if (um.secondarymeta) {
stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um)), metabehind.stack_index());
stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um)), metabehind.stack_index());
}
stack::set_field(L, metatable_key, metabehind, t.stack_index());
metabehind.pop();

View File

@ -1191,3 +1191,58 @@ end
lua["func"](bar);
});
}
TEST_CASE("usertype/vars", "usertype vars can bind various class items") {
static int muh_variable = 25;
static int through_variable = 10;
sol::state lua;
lua.open_libraries();
struct test {};
lua.new_usertype<test>("test",
"straight", sol::var(2),
"global", sol::var(muh_variable),
"ref_global", sol::var(std::ref(muh_variable)),
"global2", sol::var(through_variable),
"ref_global2", sol::var(std::ref(through_variable))
);
lua.script(R"(
t = test.new()
print(t.global)
t.global = 50
print(t.global)
)");
int mv = lua["test"]["global"];
REQUIRE(mv == 50);
REQUIRE(muh_variable == 25);
lua.script(R"(
print(t.ref_global)
t.ref_global = 50
print(t.ref_global)
)");
int rmv = lua["test"]["ref_global"];
REQUIRE(rmv == 50);
REQUIRE(muh_variable == 50);
REQUIRE(through_variable == 10);
lua.script(R"(
print(test.global2)
test.global2 = 35
print(test.global2)
)");
int tv = lua["test"]["global2"];
REQUIRE(through_variable == 10);
REQUIRE(tv == 35);
lua.script(R"(
print(test.ref_global2)
test.ref_global2 = 35
print(test.ref_global2)
)");
int rtv = lua["test"]["ref_global2"];
REQUIRE(rtv == 35);
REQUIRE(through_variable == 35);
}