From dc05552e8115e37c5d689f27c801d539397221d0 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Sat, 6 Aug 2016 17:29:07 -0400 Subject: [PATCH] sol::var is now in business --- docs/source/api/simple_usertype.rst | 1 + docs/source/api/usertype.rst | 4 +++ sol/call.hpp | 16 +++++++++ sol/function_types.hpp | 9 +++-- sol/property.hpp | 19 +++++++++- sol/usertype_metatable.hpp | 11 ++++-- test_usertypes.cpp | 55 +++++++++++++++++++++++++++++ 7 files changed, 109 insertions(+), 6 deletions(-) diff --git a/docs/source/api/simple_usertype.rst b/docs/source/api/simple_usertype.rst index 9284c34b..0447f4a6 100644 --- a/docs/source/api/simple_usertype.rst +++ b/docs/source/api/simple_usertype.rst @@ -11,4 +11,5 @@ This type is no different from :doc:`regular usertype`, but with the f - :doc:`properties` 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`` diff --git a/docs/source/api/usertype.rst b/docs/source/api/usertype.rst index 0b1a60dc..f3266696 100644 --- a/docs/source/api/usertype.rst +++ b/docs/source/api/usertype.rst @@ -226,6 +226,10 @@ Then, to register the base classes explicitly: sol::base_classes, sol::bases() ); +.. 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. diff --git a/sol/call.hpp b/sol/call.hpp index b4973039..7a837825 100644 --- a/sol/call.hpp +++ b/sol/call.hpp @@ -170,6 +170,20 @@ namespace sol { } }; + template + struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, C> { + template + 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>(L, 3 + boost); + return 0; + } + } + }; + template struct agnostic_lua_call_wrapper { static int call(lua_State* L, lua_r_CFunction f) { @@ -468,6 +482,8 @@ namespace sol { template struct is_var_bind> : std::true_type {}; + template + struct is_var_bind> : std::true_type {}; } // call_detail template diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 96f087e8..66c05bf7 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -196,9 +196,12 @@ namespace sol { return stack::push(L, detail::forward_get(fp.params)...); } - template - static int push(lua_State* L, FP&& fp) { - return push_func(std::make_index_sequence(), L, std::forward(fp)); + static int push(lua_State* L, const function_arguments& fp) { + return push_func(std::make_index_sequence(), L, fp); + } + + static int push(lua_State* L, function_arguments&& fp) { + return push_func(std::make_index_sequence(), L, std::move(fp)); } }; diff --git a/sol/property.hpp b/sol/property.hpp index 55feb8ca..5a785d3c 100644 --- a/sol/property.hpp +++ b/sol/property.hpp @@ -75,11 +75,28 @@ namespace sol { // Allow someone to make a member variable readonly (const) template - auto readonly(R T::* v) { + inline auto readonly(R T::* v) { typedef const R C; return static_cast(v); } + template + struct var_wrapper { + T value; + template + var_wrapper(Args&&... args) : value(std::forward(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 + inline auto var(V&& v) { + typedef meta::unqualified_t T; + return var_wrapper(std::forward(v)); + } + } // sol #endif // SOL_PROPERTY_HPP diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index 2ee1fbb6..f91ac781 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -197,6 +197,9 @@ namespace sol { template , base_classes_tag, call_construction>::value>> void make_regs(regs_t& l, int& index, N&& n, F&&) { + if (is_variable_binding>::value) { + return; + } luaL_Reg reg = usertype_detail::make_reg(std::forward(n), make_func()); // Returnable scope // That would be a neat keyword for C++ @@ -223,7 +226,7 @@ namespace sol { usertype_metatable(Args&&... args) : functions(std::forward(args)...), indexfunc(usertype_detail::indexing_fail), newindexfunc(usertype_detail::indexing_fail), destructfunc(nullptr), callconstructfunc(nullptr), baseclasscheck(nullptr), baseclasscast(nullptr), - mustindex(contains_variable() || contains_index()), secondarymeta(false) { + mustindex(contains_variable() || contains_index()), secondarymeta(contains_variable()) { } template @@ -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(); diff --git a/test_usertypes.cpp b/test_usertypes.cpp index af04dd15..9ee3148b 100644 --- a/test_usertypes.cpp +++ b/test_usertypes.cpp @@ -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", + "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); +}