From b7b63668c856acab6a98dca9b2c8e196b9bad3dd Mon Sep 17 00:00:00 2001 From: ThePhD Date: Mon, 20 Feb 2017 03:44:41 -0500 Subject: [PATCH] Ensure construction of special types in `simple_usertype` is working, and for regular usertype as well. --- docs/source/_themes/sol2/layout.html | 26 ++++++------ docs/source/_themes/sol2/static/sol2.css_t | 34 ++++++++-------- docs/source/_themes/sol2/theme.conf | 6 +-- docs/source/api/usertype.rst | 8 ++-- sol/call.hpp | 8 +++- sol/function_types.hpp | 12 ++++++ test_simple_usertypes.cpp | 37 +++++++++++++---- test_usertypes.cpp | 47 +++++++++++++++------- 8 files changed, 118 insertions(+), 60 deletions(-) diff --git a/docs/source/_themes/sol2/layout.html b/docs/source/_themes/sol2/layout.html index 72ec9bc1..2510f0e8 100644 --- a/docs/source/_themes/sol2/layout.html +++ b/docs/source/_themes/sol2/layout.html @@ -1,14 +1,14 @@ -{%- extends "haiku/layout.html" %} - -{% block haikuheader %} -
- {{ super() }} -
-
-

Search the Documentation

-
- - -
-
+{%- extends "haiku/layout.html" %} + +{% block haikuheader %} +
+ {{ super() }} +
+
+

Search the Documentation

+
+ + +
+
{% endblock %} \ No newline at end of file diff --git a/docs/source/_themes/sol2/static/sol2.css_t b/docs/source/_themes/sol2/static/sol2.css_t index 2db68940..b0ab0dc1 100644 --- a/docs/source/_themes/sol2/static/sol2.css_t +++ b/docs/source/_themes/sol2/static/sol2.css_t @@ -1,18 +1,18 @@ -@import url('haiku.css'); - -.header-left { - float: left; - display: inline-block; - vertical-align: top; -} - -.header-right { - float: right; - display: inline-block; - vertical-align: top; -} - -.header-right h3 { - margin: 0; - padding-top: 15px; +@import url('haiku.css'); + +.header-left { + float: left; + display: inline-block; + vertical-align: top; +} + +.header-right { + float: right; + display: inline-block; + vertical-align: top; +} + +.header-right h3 { + margin: 0; + padding-top: 15px; } \ No newline at end of file diff --git a/docs/source/_themes/sol2/theme.conf b/docs/source/_themes/sol2/theme.conf index fe5b31db..03601ad9 100644 --- a/docs/source/_themes/sol2/theme.conf +++ b/docs/source/_themes/sol2/theme.conf @@ -1,4 +1,4 @@ -[theme] -inherit = haiku -stylesheet = sol2.css +[theme] +inherit = haiku +stylesheet = sol2.css pygments_style = autumn \ No newline at end of file diff --git a/docs/source/api/usertype.rst b/docs/source/api/usertype.rst index bd941c52..03e1165f 100644 --- a/docs/source/api/usertype.rst +++ b/docs/source/api/usertype.rst @@ -163,10 +163,6 @@ If you don't specify any constructor options at all and the type is `default_con + The functions can take any form and return anything, since they're just considered to be some plain function and no placement new or otherwise needs to be done. Results from this function will be pushed into Lua according to the same rules as everything else. + Can be used to stop the generation of a ``.new()`` default constructor since a ``sol::factories`` entry will be recognized as a constructor for the usertype + If this is not sufficient, see next 2 entries on how to specifically block a constructor -* ``{anything}, sol::no_constructor`` - - Specifically tells Sol not to create a ``.new()`` if one is not specified and the type is default-constructible - - ``{anything}`` should probably be ``"new"``, which will specifically block its creation and give a proper warning if someone calls ``new`` (otherwise it will just give a nil value error) - - *Combine with the next one to only allow a factory function for your function type* * ``{anything}, {some_factory_function}`` - Essentially binds whatever the function is to name ``{anything}`` - When used WITH the ``sol::no_constructor`` option above (e.g. ``"new", sol::no_constructor`` and after that having ``"create", &my_creation_func``), one can remove typical constructor avenues and then only provide specific factory functions. Note that this combination is similar to using the ``sol::factories`` method mentioned earlier in this list. To control the destructor as well, see further below @@ -174,6 +170,10 @@ If you don't specify any constructor options at all and the type is `default_con - The purpose of this is to enable the syntax ``local v = my_class( 24 )`` and have that call a constructor; it has no other purpose - This is compatible with luabind, kaguya and other Lua library syntaxes and looks similar to C++ syntax, but the general consensus in Programming with Lua and other places is to use a function named ``new`` - Note that with the ``sol::call_constructor`` key, a construct type above must be specified. A free function without it will pass in the metatable describing this object as the first argument without that distinction, which can cause strange runtime errors. +* ``{anything}, sol::no_constructor`` + - Specifically tells Sol not to create a ``.new()`` if one is not specified and the type is default-constructible + - When the key ``{anything}`` is called on the table, it will result in an error. The error might be that the type is not-constructible. + - *Use this plus some of the above to allow a factory function for your function type but prevent other types of constructor idioms in Lua* usertype destructor options +++++++++++++++++++++++++++ diff --git a/sol/call.hpp b/sol/call.hpp index d09cc023..cbe4e2cf 100644 --- a/sol/call.hpp +++ b/sol/call.hpp @@ -28,6 +28,12 @@ #include "stack.hpp" namespace sol { + namespace function_detail { + inline int no_construction_error(lua_State* L) { + return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); + } + } + namespace call_detail { template @@ -244,7 +250,7 @@ namespace sol { template struct agnostic_lua_call_wrapper { static int call(lua_State* L, const no_construction&) { - return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); + return function_detail::no_construction_error(L); } }; diff --git a/sol/function_types.hpp b/sol/function_types.hpp index fcedaa01..492ea3c4 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -333,6 +333,18 @@ namespace sol { } }; + template <> + struct pusher { + static int push(lua_State* L, no_construction) { + lua_CFunction cf = &function_detail::no_construction_error; + return stack::push(L, cf); + } + + static int push(lua_State* L, no_construction c, function_detail::call_indicator) { + return push(L, c); + } + }; + template struct pusher>> { static int push(lua_State* L, detail::tagged>) { diff --git a/test_simple_usertypes.cpp b/test_simple_usertypes.cpp index 528cc1b1..0df606d0 100644 --- a/test_simple_usertypes.cpp +++ b/test_simple_usertypes.cpp @@ -541,15 +541,12 @@ TEST_CASE("usertype/simple-call-constructor", "ensure that all kinds of call-bas auto vfactories = sol::factories( [](const sol::table& tbl) { - for (auto v : tbl) - { - REQUIRE(v.second.valid()); - - // This fails only when the call_constructor is used: - REQUIRE(v.second.is()); + for (auto v : tbl) { + REQUIRE(v.second.valid()); + REQUIRE(v.second.is()); + } + return v_test(); } - return v_test(); - } ); lua.new_simple_usertype("v_test", @@ -568,6 +565,30 @@ 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") { + struct thing {}; + + SECTION("new no_constructor") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_simple_usertype("thing", + sol::meta_function::construct, sol::no_constructor + ); + REQUIRE_THROWS(lua.script("a = thing.new()")); + } + + SECTION("call no_constructor") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_simple_usertype("thing", + sol::call_constructor, sol::no_constructor + ); + REQUIRE_THROWS(lua.script("a = thing()")); + } +} + TEST_CASE("usertype/simple-missing-key", "make sure a missing key returns nil") { struct thing {}; diff --git a/test_usertypes.cpp b/test_usertypes.cpp index 7478c58a..280b3fb5 100644 --- a/test_usertypes.cpp +++ b/test_usertypes.cpp @@ -1036,28 +1036,47 @@ TEST_CASE("usertype/blank_constructor", "make sure lua types cannot be construct TEST_CASE("usertype/no_constructor", "make sure lua types cannot be constructed if a blank / empty constructor is provided") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - SECTION("order1") - { + + SECTION("order1") { + sol::state lua; + lua.open_libraries(sol::lib::base); lua.new_usertype("thing", - "v", &thing::v - , sol::call_constructor, sol::no_constructor + "v", &thing::v, + sol::call_constructor, sol::no_constructor ); - REQUIRE_THROWS(lua.script("t = thing.new()")); + REQUIRE_THROWS(lua.script("t = thing()")); } - SECTION("order2") - { - lua.new_usertype("thing" - , sol::call_constructor, sol::no_constructor - , "v", &thing::v + SECTION("order2") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("thing", + sol::call_constructor, sol::no_constructor, + "v", &thing::v ); REQUIRE_THROWS(lua.script("t = thing.new()")); } - REQUIRE_THROWS(lua.script("t = thing.new()")); + SECTION("new no_constructor") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("thing", + sol::meta_function::construct, sol::no_constructor + ); + REQUIRE_THROWS(lua.script("a = thing.new()")); + } + + SECTION("call no_constructor") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("thing", + sol::call_constructor, sol::no_constructor + ); + REQUIRE_THROWS(lua.script("a = thing()")); + } } TEST_CASE("usertype/coverage", "try all the things") {