diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index d0a56239..0f2712d9 100644 --- a/single/sol/sol.hpp +++ b/single/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2017-03-22 11:54:07.623956 UTC -// This header was generated with sol v2.16.0 (revision a9644d0) +// Generated 2017-03-23 14:12:13.335349 UTC +// This header was generated with sol v2.16.0 (revision 6ceb715) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -10424,13 +10424,14 @@ namespace sol { bool haslessequals; template >> = meta::enabler> - inline lua_CFunction make_func() { + lua_CFunction make_func() const { return std::get(functions); } template >> = meta::enabler> - inline lua_CFunction make_func() { - return call; + lua_CFunction make_func() const { + const auto& name = std::get(functions); + return (usertype_detail::make_shim(name) == "__newindex") ? &call : &call; } static bool contains_variable() { @@ -10522,6 +10523,17 @@ namespace sol { ++index; } + template + static std::pair make_call_info(std::string n) { + return{ n, (n == "__newindex" || n == "__index") ? + usertype_detail::call_information(&usertype_metatable::real_meta_call, + &usertype_metatable::real_meta_call) + : + usertype_detail::call_information(&usertype_metatable::real_find_call, + &usertype_metatable::real_find_call) + }; + } + template > usertype_metatable(Args&&... args) : mapping(), @@ -10535,9 +10547,7 @@ namespace sol { hasequals(false), hasless(false), haslessequals(false) { std::initializer_list ilist{ { std::pair( - usertype_detail::make_string(std::get(functions)), - usertype_detail::call_information(&usertype_metatable::real_find_call, - &usertype_metatable::real_find_call) + make_call_info(usertype_detail::make_string(std::get(functions))) ) }... }; mapping.insert(ilist); @@ -10554,7 +10564,15 @@ namespace sol { if (is_variable_binding(f.functions))>::value) { return real_call_with(L, f); } - return stack::push(L, c_closure(call, stack::push(L, light(f)))); + int upvalues = stack::push(L, light(f)); + auto cfunc = &call; + return stack::push(L, c_closure(cfunc, upvalues)); + } + + template + static int real_meta_call(lua_State* L, void* um, int) { + auto& f = *static_cast(um); + return real_call_with(L, f); } template diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index 8210fc05..81df4e1e 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -334,13 +334,14 @@ namespace sol { bool haslessequals; template >> = meta::enabler> - inline lua_CFunction make_func() { + lua_CFunction make_func() const { return std::get(functions); } template >> = meta::enabler> - inline lua_CFunction make_func() { - return call; + lua_CFunction make_func() const { + const auto& name = std::get(functions); + return (usertype_detail::make_shim(name) == "__newindex") ? &call : &call; } static bool contains_variable() { @@ -432,6 +433,17 @@ namespace sol { ++index; } + template + static std::pair make_call_info(std::string n) { + return{ n, (n == "__newindex" || n == "__index") ? + usertype_detail::call_information(&usertype_metatable::real_meta_call, + &usertype_metatable::real_meta_call) + : + usertype_detail::call_information(&usertype_metatable::real_find_call, + &usertype_metatable::real_find_call) + }; + } + template > usertype_metatable(Args&&... args) : mapping(), @@ -445,9 +457,7 @@ namespace sol { hasequals(false), hasless(false), haslessequals(false) { std::initializer_list ilist{ { std::pair( - usertype_detail::make_string(std::get(functions)), - usertype_detail::call_information(&usertype_metatable::real_find_call, - &usertype_metatable::real_find_call) + make_call_info(usertype_detail::make_string(std::get(functions))) ) }... }; mapping.insert(ilist); @@ -464,7 +474,15 @@ namespace sol { if (is_variable_binding(f.functions))>::value) { return real_call_with(L, f); } - return stack::push(L, c_closure(call, stack::push(L, light(f)))); + int upvalues = stack::push(L, light(f)); + auto cfunc = &call; + return stack::push(L, c_closure(cfunc, upvalues)); + } + + template + static int real_meta_call(lua_State* L, void* um, int) { + auto& f = *static_cast(um); + return real_call_with(L, f); } template diff --git a/test_simple_usertypes.cpp b/test_simple_usertypes.cpp index d4a5d045..aa8a47ab 100644 --- a/test_simple_usertypes.cpp +++ b/test_simple_usertypes.cpp @@ -8,7 +8,7 @@ #include #include -TEST_CASE("usertype/simple-usertypes", "Ensure that simple usertypes properly work here") { +TEST_CASE("simple_usertype/usertypes", "Ensure that simple usertypes properly work here") { struct marker { bool value = false; }; @@ -87,7 +87,7 @@ TEST_CASE("usertype/simple-usertypes", "Ensure that simple usertypes properly wo REQUIRE(z == 29); } -TEST_CASE("usertype/simple-usertypes-constructors", "Ensure that calls with specific arguments work") { +TEST_CASE("simple_usertype/usertypes-constructors", "Ensure that calls with specific arguments work") { struct marker { bool value = false; }; @@ -173,7 +173,7 @@ TEST_CASE("usertype/simple-usertypes-constructors", "Ensure that calls with spec REQUIRE(z == 29); } -TEST_CASE("usertype/simple-shared-ptr-regression", "simple usertype metatables should not screw over unique usertype metatables") { +TEST_CASE("simple_usertype/shared-ptr-regression", "simple usertype metatables should not screw over unique usertype metatables") { static int created = 0; static int destroyed = 0; struct test { @@ -211,7 +211,7 @@ TEST_CASE("usertype/simple-shared-ptr-regression", "simple usertype metatables s REQUIRE(destroyed == 1); } -TEST_CASE("usertype/simple-vars", "simple usertype vars can bind various values (no ref)") { +TEST_CASE("simple_usertype/vars", "simple usertype vars can bind various values (no ref)") { int muh_variable = 10; int through_variable = 25; @@ -249,7 +249,7 @@ g3 = test.global3 REQUIRE(g3 == 20); } -TEST_CASE("usertypes/simple-variable-control", "test to see if usertypes respond to inheritance and variable controls") { +TEST_CASE("simple_usertype/variable-control", "test to see if usertypes respond to inheritance and variable controls") { class A { public: virtual void a() { throw std::runtime_error("entered base pure virtual implementation"); }; @@ -322,7 +322,7 @@ TEST_CASE("usertypes/simple-variable-control", "test to see if usertypes respond lua.script("print(sw.pb)assert(sw.pb == 27)"); } -TEST_CASE("usertype/simple-factory-constructor-overload-usage", "simple usertypes should probably invoke types") { +TEST_CASE("simple_usertype/factory-constructor-overload-usage", "simple usertypes should probably invoke types") { class A { public: virtual void a() { throw std::runtime_error("entered base pure virtual implementation"); }; @@ -378,7 +378,7 @@ TEST_CASE("usertype/simple-factory-constructor-overload-usage", "simple usertype REQUIRE(y4 == 3); } -TEST_CASE("usertype/simple-runtime-append", "allow extra functions to be appended at runtime directly to the metatable itself") { +TEST_CASE("simple_usertype/runtime-append", "allow extra functions to be appended at runtime directly to the metatable itself") { class A { }; @@ -407,7 +407,7 @@ TEST_CASE("usertype/simple-runtime-append", "allow extra functions to be appende REQUIRE(w == 100); } -TEST_CASE("usertype/simple-destruction-test", "make sure usertypes are properly destructed and don't double-delete memory or segfault") { +TEST_CASE("simple_usertype/destruction-test", "make sure usertypes are properly destructed and don't double-delete memory or segfault") { sol::state lua; class CrashClass { @@ -438,7 +438,7 @@ TEST_CASE("usertype/simple-destruction-test", "make sure usertypes are properly } } -TEST_CASE("usertype/simple-table-append", "Ensure that appending to the meta table also affects the internal function table for pointers as well") { +TEST_CASE("simple_usertype/table-append", "Ensure that appending to the meta table also affects the internal function table for pointers as well") { struct A { int func() { return 5000; @@ -462,7 +462,7 @@ TEST_CASE("usertype/simple-table-append", "Ensure that appending to the meta tab }()); } -TEST_CASE("usertype/simple-class-propogation", "make sure methods and variables from base classes work properly in SAFE_USERTYPE mode") { +TEST_CASE("simple_usertype/class-propogation", "make sure methods and variables from base classes work properly in SAFE_USERTYPE mode") { class A { public: int var = 200; @@ -488,7 +488,7 @@ TEST_CASE("usertype/simple-class-propogation", "make sure methods and variables )"); } -TEST_CASE("usertype/simple-call-constructor", "ensure that all kinds of call-based constructors can be serialized") { +TEST_CASE("simple_usertype/call-constructor", "ensure that all kinds of call-based constructors can be serialized") { struct thing {}; struct v_test { @@ -565,7 +565,7 @@ TEST_CASE("usertype/simple-call-constructor", "ensure that all kinds of call-bas } } -TEST_CASE("usertype/simple-no_constructor", "make sure simple usertype errors when no-constructor types are called") { +TEST_CASE("simple_usertype/no_constructor", "make sure simple usertype errors when no-constructor types are called") { struct thing {}; SECTION("new no_constructor") { @@ -589,7 +589,7 @@ TEST_CASE("usertype/simple-no_constructor", "make sure simple usertype errors wh } } -TEST_CASE("usertype/simple-missing-key", "make sure a missing key returns nil") { +TEST_CASE("simple_usertype/missing-key", "make sure a missing key returns nil") { struct thing {}; sol::state lua; @@ -599,7 +599,7 @@ TEST_CASE("usertype/simple-missing-key", "make sure a missing key returns nil") REQUIRE_NOTHROW(lua.script("print(thing.missingKey)")); } -TEST_CASE("usertype/simple-runtime-extensibility", "Check if usertypes are runtime extensible") { +TEST_CASE("simple_usertype/runtime-extensibility", "Check if usertypes are runtime extensible") { struct thing { int v = 20; int func(int a) { return a; } @@ -696,3 +696,56 @@ end REQUIRE(val == 3); } } + +TEST_CASE("simple_usertype/meta-key-retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") { + SECTION("dynamically") { + static int writes = 0; + static std::string keys[2] = {}; + static int values[2] = {}; + struct d_sample { + void foo(std::string k, int v) { + keys[writes] = k; + values[writes] = v; + ++writes; + } + }; + + sol::state state; + state.new_simple_usertype("sample"); + sol::table s = state["sample"]["new"](); + s[sol::metatable_key][sol::meta_function::new_index] = &d_sample::foo; + state["var"] = s; + + + state.script("var.key = 2"); + state.script("var.__newindex = 4"); + REQUIRE(values[0] == 2); + REQUIRE(keys[0] == "key"); + REQUIRE(values[1] == 4); + REQUIRE(keys[1] == "__newindex"); + } + + SECTION("statically") { + static int writes = 0; + static std::string keys[2] = {}; + static int values[2] = {}; + struct sample { + void foo(std::string k, int v) { + keys[writes] = k; + values[writes] = v; + ++writes; + } + }; + + sol::state state; + state.new_simple_usertype("sample", sol::meta_function::new_index, &sample::foo); + + state.script("var = sample.new()"); + state.script("var.key = 2"); + state.script("var.__newindex = 4"); + REQUIRE(values[0] == 2); + REQUIRE(keys[0] == "key"); + REQUIRE(values[1] == 4); + REQUIRE(keys[1] == "__newindex"); + } +} diff --git a/test_usertypes.cpp b/test_usertypes.cpp index 22689110..20a4d35a 100644 --- a/test_usertypes.cpp +++ b/test_usertypes.cpp @@ -1354,7 +1354,7 @@ print(test.ref_global2) REQUIRE(through_variable == 35); } -TEST_CASE("usertypes/var-and-property", "make sure const vars are readonly and properties can handle lambdas") { +TEST_CASE("usertype/var-and-property", "make sure const vars are readonly and properties can handle lambdas") { const static int arf = 20; struct test { @@ -1622,3 +1622,56 @@ end REQUIRE(val == 3); } } + +TEST_CASE("usertype/meta-key-retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") { + SECTION("dynamically") { + static int writes = 0; + static std::string keys[2] = {}; + static int values[2] = {}; + struct d_sample { + void foo(std::string k, int v) { + keys[writes] = k; + values[writes] = v; + ++writes; + } + }; + + sol::state state; + state.new_usertype("sample"); + sol::table s = state["sample"]["new"](); + s[sol::metatable_key][sol::meta_function::new_index] = &d_sample::foo; + state["var"] = s; + + + state.script("var.key = 2"); + state.script("var.__newindex = 4"); + REQUIRE(values[0] == 2); + REQUIRE(keys[0] == "key"); + REQUIRE(values[1] == 4); + REQUIRE(keys[1] == "__newindex"); + } + + SECTION("statically") { + static int writes = 0; + static std::string keys[2] = {}; + static int values[2] = {}; + struct sample { + void foo(std::string k, int v) { + keys[writes] = k; + values[writes] = v; + ++writes; + } + }; + + sol::state state; + state.new_usertype("sample", sol::meta_function::new_index, &sample::foo); + + state.script("var = sample.new()"); + state.script("var.key = 2"); + state.script("var.__newindex = 4"); + REQUIRE(values[0] == 2); + REQUIRE(keys[0] == "key"); + REQUIRE(values[1] == 4); + REQUIRE(keys[1] == "__newindex"); + } +}