diff --git a/docs/source/conf.py b/docs/source/conf.py index 2aa5c3a2..8c5b5dde 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -61,7 +61,7 @@ author = 'ThePhD' # The short X.Y version. version = '2.14' # The full version, including alpha/beta/rc tags. -release = '2.14.10' +release = '2.14.12' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/index.rst b/docs/source/index.rst index 6e10ab70..e2bac16c 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -18,6 +18,11 @@ When you need to hit the ground running with Lua and C++, `Sol`_ is the go-to fr :target: https://travis-ci.org/ThePhD/sol2 :alt: build status +.. image:: https://badges.gitter.im/chat-sol2/Lobby.svg + target: https://gitter.im/chat-sol2/Lobby + :alt: chat about sol2 on gitter + + get going: ---------- @@ -28,6 +33,7 @@ get going: tutorial/all-the-things tutorial/tutorial-top features + usertypes api/api-top mentions benchmarks @@ -43,7 +49,7 @@ get going: "I need feature X, maybe you have it?" -------------------------------------- -Take a look at the :doc:`Features` page: it links to much of the API. You can also just straight up browse the :doc:`api` or ease in with the :doc:`tutorials`. To know how function arguments are handled, see :ref:`this note`. Don't see a feature you want? Send inquiries for support for a particular abstraction to the `issues`_ tracker. +Take a look at the :doc:`Features` page: it links to much of the API. You can also just straight up browse the :doc:`api` or ease in with the :doc:`tutorials`. To know more about the implementation for usertypes, see :doc:`here` To know how function arguments are handled, see :ref:`this note`. Don't see a feature you want? Send inquiries for support for a particular abstraction to the `issues`_ tracker. the basics: diff --git a/docs/source/tutorial/customization.rst b/docs/source/tutorial/customization.rst index 31fcad46..5479c804 100644 --- a/docs/source/tutorial/customization.rst +++ b/docs/source/tutorial/customization.rst @@ -108,6 +108,9 @@ A few things of note about the implementation: First, there's an auxiliary param You can make something pushable into Lua, but not get-able in the same way if you only specialize one part of the system. If you need to retrieve it (as a return using one or multiple values from Lua), you should specialize the ``sol::stack::getter`` template class and the ``sol::stack::checker`` template class. If you need to push it into Lua at some point, then you'll want to specialize the ``sol::stack::pusher`` template class. The ``sol::lua_size`` template class trait needs to be specialized for both cases, unless it only pushes 1 item, in which case the default implementation will assume 1. +.. note:: + + It is important to note here that the ``getter``, ``pusher`` and ``checker`` differentiate between a type ``T`` and a pointer to a type ``T*``. This means that if you want to work purely with, say, a ``T*`` handle that does not have the same semantics as just ``T``, you may need to specify checkers/getters/pushers for both ``T*`` and ``T``. The checkers for ``T*`` forward to the checkers for ``T``, but the getter for ``T*`` does not forward to the getter for ``T`` (e.g., because of ``int*`` not being quite the same as ``int``). In general, this is fine since most getters/checkers only use 1 stack point. But, if you're doing more complex nested classes, it would be useful to use ``tracking.last`` to understand how many stack indices the last getter/checker operation did and increment it by ``index + tracking.last`` after using a ``stack::check<..>( L, index, tracking)`` call. diff --git a/docs/source/usertypes.rst b/docs/source/usertypes.rst new file mode 100644 index 00000000..09d4e755 --- /dev/null +++ b/docs/source/usertypes.rst @@ -0,0 +1,25 @@ +usertypes +========= + +Perhaps the most powerful feature of sol2, ``usertypes`` are the way sol2 and C++ communicate your classes to the Lua runtime and bind things between both tables and to specific blocks of C++ memory, allowing you to treat Lua userdata and other things like classes. + +To learn more about usertypes, visit: + +* :doc:`tutorial` +* :doc:`customization point tutorial` +* :doc:`api documentation` +* :doc:`memory documentation` + +There are also some notes about guarantees you can find about usertypes, and their associated userdata, below: + +* You can push types classified as userdata before you register a usertype. + - You can register a usertype with the Lua runtime at any time sol2 + - You can retrieve them from the Lua runtime as well through sol2 + - Methods and properties will be added to the type only after you register it in the Lua runtime +* Types either copy once or move once into the memory location, if it is a value type. If it is a pointer, we store only the reference. + - This means take arguments of class types (not primitive types like strings or integers) by ``T&`` or ``T*`` to modify the data in Lua directly, or by plain ``T`` to get a copy + - Return types and passing arguments to ``sol::function`` use perfect forwarding and reference semantics, which means no copies happen unless you specify a value explicitly. See :ref:`this note for details`. +* The first ``sizeof( void* )`` bytes is always a pointer to the typed C++ memory. What comes after is based on what you've pushed into the system according to :doc:`the memory specification for usertypes`. This is compatible with a number of systems. +* Member methods, properties, variables and functions taking ``self&`` arguments modify data directly + - Work on a copy by taking or returning a copy by value. +* The actual metatable associated with the usertype has a long name and is defined to be opaque by the Sol implementation. \ No newline at end of file diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index fb0818be..a7ded045 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 2016-10-21 21:30:36.718233 UTC -// This header was generated with sol v2.14.11 (revision 8c3ae42) +// Generated 2016-10-23 21:02:40.993304 UTC +// This header was generated with sol v2.14.12 (revision 2ac711b) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -5063,7 +5063,7 @@ namespace sol { template struct getter { static T& get(lua_State* L, int index, record& tracking) { - return getter{}.get(L, index, tracking); + return getter>{}.get(L, index, tracking); } }; @@ -5459,7 +5459,7 @@ namespace sol { }; template - struct getter { + struct getter> { static T* get_no_nil(lua_State* L, int index, record& tracking) { tracking.use(1); void** pudata = static_cast(lua_touserdata(L, index)); @@ -5478,28 +5478,49 @@ namespace sol { T* obj = static_cast(udata); return obj; } + + static T& get(lua_State* L, int index, record& tracking) { + return *get_no_nil(L, index, tracking); + } + }; + template + struct getter> { static T* get(lua_State* L, int index, record& tracking) { type t = type_of(L, index); if (t == type::nil) { tracking.use(1); return nullptr; } - return get_no_nil(L, index, tracking); + return getter>::get_no_nil(L, index, tracking); } }; template struct getter> { static T* get(lua_State* L, int index, record& tracking) { - return getter::get_no_nil(L, index, tracking); + return getter>::get_no_nil(L, index, tracking); } }; template struct getter { static T& get(lua_State* L, int index, record& tracking) { - return *getter::get_no_nil(L, index, tracking); + return getter>::get(L, index, tracking); + } + }; + + template + struct getter> { + static T& get(lua_State* L, int index, record& tracking) { + return getter{}.get(L, index, tracking); + } + }; + + template + struct getter { + static T* get(lua_State* L, int index, record& tracking) { + return getter>::get(L, index, tracking); } }; @@ -5517,13 +5538,6 @@ namespace sol { } }; - template - struct getter> { - static T& get(lua_State* L, int index, record& tracking) { - return getter{}.get(L, index, tracking); - } - }; - template struct getter> { typedef std::tuple(nullptr, 0))...> R; @@ -7427,11 +7441,50 @@ namespace sol { } return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); } + + template + inline int overload_match_arity_single(types<>, std::index_sequence<>, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + + template + inline int overload_match_arity_single(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + typedef lua_bind_traits> traits; + typedef meta::tuple_types return_types; + typedef typename traits::free_args_list args_list; + // compile-time eliminate any functions that we know ahead of time are of improper arity + if (meta::find_in_pack_v, index_value...>::value) { + return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + if (traits::free_arity != fxarity) { + return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); + } + + template + inline int overload_match_arity_single(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + typedef lua_bind_traits> traits; + typedef meta::tuple_types return_types; + typedef typename traits::free_args_list args_list; + // compile-time eliminate any functions that we know ahead of time are of improper arity + if (meta::find_in_pack_v, index_value...>::value) { + return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + if (traits::free_arity != fxarity) { + return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + stack::record tracking{}; + if (!stack::stack_detail::check_types{}.check(args_list(), L, start, no_panic, tracking)) { + return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); + } } // overload_detail template inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - return overload_detail::overload_match_arity(types(), std::make_index_sequence(), std::index_sequence<>(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + return overload_detail::overload_match_arity_single(types(), std::make_index_sequence(), std::index_sequence<>(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } template diff --git a/sol/call.hpp b/sol/call.hpp index 7e46a459..9f6a3af8 100644 --- a/sol/call.hpp +++ b/sol/call.hpp @@ -57,7 +57,7 @@ namespace sol { template int operator()(types, index_value, types r, types a, lua_State* L, int, int start) const { detail::default_construct func{}; - return stack::call_into_lua(r, a, L, start, func, obj); + return stack::call_into_lua(r, a, L, start, func, obj); } }; @@ -85,11 +85,50 @@ namespace sol { } return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); } + + template + inline int overload_match_arity_single(types<>, std::index_sequence<>, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + + template + inline int overload_match_arity_single(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + typedef lua_bind_traits> traits; + typedef meta::tuple_types return_types; + typedef typename traits::free_args_list args_list; + // compile-time eliminate any functions that we know ahead of time are of improper arity + if (meta::find_in_pack_v, index_value...>::value) { + return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + if (traits::free_arity != fxarity) { + return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); + } + + template + inline int overload_match_arity_single(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { + typedef lua_bind_traits> traits; + typedef meta::tuple_types return_types; + typedef typename traits::free_args_list args_list; + // compile-time eliminate any functions that we know ahead of time are of improper arity + if (meta::find_in_pack_v, index_value...>::value) { + return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + if (traits::free_arity != fxarity) { + return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + stack::record tracking{}; + if (!stack::stack_detail::check_types{}.check(args_list(), L, start, no_panic, tracking)) { + return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); + } } // overload_detail template inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - return overload_detail::overload_match_arity(types(), std::make_index_sequence(), std::index_sequence<>(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + return overload_detail::overload_match_arity_single(types(), std::make_index_sequence(), std::index_sequence<>(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } template diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index 314fc909..5a8610f2 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -267,21 +267,7 @@ namespace sol { }; template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - const type indextype = type_of(L, index); - // Allow nil to be transformed to nullptr - if (indextype == type::nil) { - tracking.use(1); - return true; - } - return checker, type::userdata, C>{}.check(types>(), L, indextype, index, std::forward(handler), tracking); - } - }; - - template - struct checker { + struct checker, type::userdata, C> { template static bool check(types, lua_State* L, type indextype, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -320,11 +306,28 @@ namespace sol { lua_pop(L, 1); return true; } + }; + template + struct checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { const type indextype = type_of(L, index); - return check(types(), L, indextype, index, std::forward(handler), tracking); + return checker, type::userdata, C>{}.check(types(), L, indextype, index, std::forward(handler), tracking); + } + }; + + template + struct checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + const type indextype = type_of(L, index); + // Allow nil to be transformed to nullptr + if (indextype == type::nil) { + tracking.use(1); + return true; + } + return checker, type::userdata, C>{}.check(L, index, std::forward(handler), tracking); } }; diff --git a/sol/stack_get.hpp b/sol/stack_get.hpp index 52c52efa..7cb7f2b8 100644 --- a/sol/stack_get.hpp +++ b/sol/stack_get.hpp @@ -41,7 +41,7 @@ namespace sol { template struct getter { static T& get(lua_State* L, int index, record& tracking) { - return getter{}.get(L, index, tracking); + return getter>{}.get(L, index, tracking); } }; @@ -437,7 +437,7 @@ namespace sol { }; template - struct getter { + struct getter> { static T* get_no_nil(lua_State* L, int index, record& tracking) { tracking.use(1); void** pudata = static_cast(lua_touserdata(L, index)); @@ -456,28 +456,49 @@ namespace sol { T* obj = static_cast(udata); return obj; } + + static T& get(lua_State* L, int index, record& tracking) { + return *get_no_nil(L, index, tracking); + } + }; + template + struct getter> { static T* get(lua_State* L, int index, record& tracking) { type t = type_of(L, index); if (t == type::nil) { tracking.use(1); return nullptr; } - return get_no_nil(L, index, tracking); + return getter>::get_no_nil(L, index, tracking); } }; template struct getter> { static T* get(lua_State* L, int index, record& tracking) { - return getter::get_no_nil(L, index, tracking); + return getter>::get_no_nil(L, index, tracking); } }; template struct getter { static T& get(lua_State* L, int index, record& tracking) { - return *getter::get_no_nil(L, index, tracking); + return getter>::get(L, index, tracking); + } + }; + + template + struct getter> { + static T& get(lua_State* L, int index, record& tracking) { + return getter{}.get(L, index, tracking); + } + }; + + template + struct getter { + static T* get(lua_State* L, int index, record& tracking) { + return getter>::get(L, index, tracking); } }; @@ -495,13 +516,6 @@ namespace sol { } }; - template - struct getter> { - static T& get(lua_State* L, int index, record& tracking) { - return getter{}.get(L, index, tracking); - } - }; - template struct getter> { typedef std::tuple(nullptr, 0))...> R;