From da28527421dee4eebe294b5c9117a1f9e48df8b0 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Sat, 1 Jul 2017 11:02:15 -0400 Subject: [PATCH] prepare for container_traits to be a thing update large parts of the documentation and add a new section to streamline information about functions --- docs/source/api/compatibility.rst | 2 +- docs/source/api/containers.rst | 2 +- docs/source/api/function.rst | 24 +------ docs/source/api/this_environment.rst | 2 + docs/source/api/types.rst | 6 +- docs/source/api/variadic_args.rst | 42 ++++++++++++- docs/source/compilation.rst | 51 ++++++++++++--- docs/source/errors.rst | 14 +---- docs/source/features.rst | 11 ++-- docs/source/functions.rst | 83 +++++++++++++++++++++++++ docs/source/index.rst | 1 + docs/source/tutorial/all-the-things.rst | 4 +- docs/source/tutorial/functions.rst | 4 +- sol/container_traits.hpp | 32 ++++++++++ test_functions.cpp | 23 +++++++ 15 files changed, 241 insertions(+), 60 deletions(-) create mode 100644 docs/source/functions.rst create mode 100644 sol/container_traits.hpp diff --git a/docs/source/api/compatibility.rst b/docs/source/api/compatibility.rst index 3299bff9..3d06213f 100644 --- a/docs/source/api/compatibility.rst +++ b/docs/source/api/compatibility.rst @@ -3,7 +3,7 @@ compatibility.hpp Lua 5.3/5.2 compatibility for Lua 5.1/LuaJIT -------------------------------------------- -This is a detail header used to maintain compatability with the 5.2 and 5.3 APIs. It contains code from the MIT-Licensed `Lua code`_ in some places and also from the `lua-compat`_ repository by KeplerProject. +This is a detail header used to maintain compatability with the 5.2 and 5.3+ APIs. It contains code from the MIT-Licensed `Lua code`_ in some places and also from the `lua-compat`_ repository by KeplerProject. It is not fully documented as this header's only purpose is for internal use to make sure Sol compiles across all platforms / distributions with no errors or missing Lua functionality. If you think there's some compatibility features we are missing or if you are running into redefinition errors, please make an `issue in the issue tracker`_. diff --git a/docs/source/api/containers.rst b/docs/source/api/containers.rst index 327e4de1..2150d245 100644 --- a/docs/source/api/containers.rst +++ b/docs/source/api/containers.rst @@ -65,7 +65,7 @@ Note that this will not work well in Lua 5.1, as it has explicit table checks an print(i, vec[i]) end -There are also other ways to iterate over key/values, but they can be difficult due to not having proper support in Lua 5.1. We recommend that you upgrade to Lua 5.2 or 5.3. +There are also other ways to iterate over key/values, but they can be difficult due to not having proper support in Lua 5.1. We recommend that you upgrade to Lua 5.2 or 5.3 if this is integral to your infrastructure. additional functions diff --git a/docs/source/api/function.rst b/docs/source/api/function.rst index 88c3b95b..fce41eec 100644 --- a/docs/source/api/function.rst +++ b/docs/source/api/function.rst @@ -84,26 +84,4 @@ This makes it much easier to work with multiple return values. Using ``std::tie` Calls the function. The second ``operator()`` lets you specify the templated return types using the ``my_func(sol::types, ...)`` syntax. Function assumes there are no runtime errors, and thusly will call the ``atpanic`` function if an error does occur. -.. _function-argument-handling: - -functions and argument passing ------------------------------- - -.. note:: - - All arguments are forwarded. Unlike :doc:`get/set/operator[] on sol::state` or :doc:`sol::table`, value semantics are not used here. It is forwarding reference semantics, which do not copy/move unless it is specifically done by the receiving functions / specifically done by the user. - - -.. note:: - - This also means that you should pass and receive arguments in certain ways to maximize efficiency. For example, ``sol::table``, ``sol::object``, ``sol::userdata`` and friends are fairly cheap to copy, and should simply by taken as values. This includes primitive types like ``int`` and ``double``. However, C++ types -- if you do not want copies -- should be taken as ``const type&`` or ``type&``, to save on copies if it's important. Note that taking references from Lua also means you can modify the data inside of Lua directly, so be careful. Lua by default deals with things mostly by reference (save for primitive types). - - You can get even more speed out of ``sol::object`` style of types by taking a ``sol::stack_object`` (or ``sol::stack_...``, where ``...`` is ``userdata``, ``reference``, ``table``, etc.). These reference a stack position directly rather than cheaply/safely the internal Lua reference to make sure it can't be swept out from under you. Note that if you manipulate the stack out from under these objects, they may misbehave, so please do not blow up your Lua stack when working with these types. - - ``std::string`` (and ``std::wstring``) are special. Lua stores strings as ``const char*`` null-terminated strings. ``std::string`` will copy, so taking a ``std::string`` by value or by const reference still invokes a copy operation. You can take a ``const char*``, but that will mean you're exposed to what happens on the Lua stack (if you change it and start chopping off function arguments from it in your function calls and such, as warned about previously). - - -function call safety --------------------- - -You can have functions here and on usertypes check to definitely make sure that the types passed to C++ functions are what they're supposed to be by adding a ``#define SOL_CHECK_ARGUMENTS`` before including Sol, or passing it on the command line. Otherwise, for speed reasons, these checks are only used where absolutely necessary (like discriminating between :doc:`overloads`). See :doc:`safety<../safety>` for more information. \ No newline at end of file +To know more about how function arguments are handled, see :ref:`this note` diff --git a/docs/source/api/this_environment.rst b/docs/source/api/this_environment.rst index 2bce4b78..7a8dd6ea 100644 --- a/docs/source/api/this_environment.rst +++ b/docs/source/api/this_environment.rst @@ -33,6 +33,8 @@ Sometimes in C++ it's useful to know where a Lua call is coming from and what :d lua["freshenv"] = freshenv; lua.set_function("f", env_check); + + // note that "f" only takes 1 argument and is okay here lua.script("f(25)", freshenv); return 0; diff --git a/docs/source/api/types.rst b/docs/source/api/types.rst index 78a59dbf..a335880d 100644 --- a/docs/source/api/types.rst +++ b/docs/source/api/types.rst @@ -216,11 +216,11 @@ structs Types that differentiate between the two kinds of ``void*`` Lua hands back from its API: full userdata and light userdata, as well as a type that modifies the index passed to ``get`` to refer to `up values`_ These types can be used to trigger different underlying API calls to Lua when working with :doc:`stack` namespace and the ``push``/``get``/``pop``/``check`` functions. -The ``raw_index`` type is used to tell a :doc:`sol::reference` type or similar that the desired index -- negative or not -- should be passed through directly to the API. +The ``raw_index`` type is used to tell a :doc:`sol::reference` type or similar that the desired index -- negative or not -- should be passed through directly to the API. -The ``absolute_index`` type is used to tell a :doc:`sol::reference` type or similar that the desired index -- negative or not -- should be passed through Lua's `lua_absindex`_ function first to adjust where it is, and then given to the underlying API. +The ``absolute_index`` type is used to tell a :doc:`sol::reference` type or similar that the desired index -- negative or not -- should be passed through Lua's `lua_absindex`_ function first to adjust where it is, and then given to the underlying API. -The ``ref_index`` type is used to tell a :doc:`sol::reference` type or similar that it should look into the Lua C Registry for its type. +The ``ref_index`` type is used to tell a :doc:`sol::reference` type or similar that it should look into the Lua C Registry for its type. .. _up values: http://www.Lua.org/manual/5.3/manual.html#4.4 .. _lua_absindex: https://www.lua.org/manual/5.3/manual.html#lua_absindex diff --git a/docs/source/api/variadic_args.rst b/docs/source/api/variadic_args.rst index 8c611b1d..6db06767 100644 --- a/docs/source/api/variadic_args.rst +++ b/docs/source/api/variadic_args.rst @@ -10,7 +10,7 @@ transparent argument to deal with multiple parameters to a function This class is meant to represent every single argument at its current index and beyond in a function list. It does not increment the argument count and is thus transparent. You can place it anywhere in the argument list, and it will represent all of the objects in a function call that come after it, whether they are listed explicitly or not. -``variadic_args`` also has ``begin()`` and ``end()`` functions that return (almost) random-acess iterators. These return a proxy type that can be implicitly converted, much like the :doc:`table proxy type`. +``variadic_args`` also has ``begin()`` and ``end()`` functions that return (almost) random-acess iterators. These return a proxy type that can be implicitly converted to a type you want, much like the :doc:`table proxy type`. .. code-block:: cpp :linenos: @@ -20,6 +20,7 @@ This class is meant to represent every single argument at its current index and int main () { sol::state lua; + lua.open_libraries(sol::lib::base); // Function requires 2 arguments // rest can be variadic, but: @@ -46,6 +47,8 @@ This class is meant to represent every single argument at its current index and lua.script("print(x)"); // 50 lua.script("print(x2)"); // 600 lua.script("print(x3)"); // 21 + + return 0; } You can also "save" arguments and the like later, by stuffing them into a ``std::vector`` or something similar that pulls out all the arguments. Below is an example of saving all of the arguments provided by ``sol::variadic_args`` in a lambda capture variable called ``args``. @@ -67,7 +70,9 @@ You can also "save" arguments and the like later, by stuffing them into a ``std: int main() { sol::state lua; lua.open_libraries(sol::lib::base); + lua.set_function("store_routine", &store_routine); + lua.script(R"( function a(name) print(name) @@ -83,5 +88,40 @@ You can also "save" arguments and the like later, by stuffing them into a ``std: store_routine(b, 20, "these apples") )"); function_storage(); + + return 0; } + +Finally, note that you can use ``sol::variadic_args`` constructor to "offset" which arguments you want: + +.. code-block:: cpp + :linenos: + + #include + + int main () { + + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.set_function("f", [](sol::variadic_args va) { + int r = 0; + sol::variadic_args shifted_va(va.lua_state(), 3); + for (auto v : shifted_va) { + int value = v; + r += value; + } + return r; + }); + + lua.script("x = f(1, 2, 3, 4)"); + lua.script("x2 = f(8, 200, 3, 4)"); + lua.script("x3 = f(1, 2, 3, 4, 5, 6)"); + + lua.script("print(x)"); // 7 + lua.script("print(x2)"); // 7 + lua.script("print(x3)"); // 18 + + return 0; + } diff --git a/docs/source/compilation.rst b/docs/source/compilation.rst index 0147e4f6..d0bbf895 100644 --- a/docs/source/compilation.rst +++ b/docs/source/compilation.rst @@ -6,29 +6,62 @@ getting good final product out of sol2 supported compilers ------------------- -GCC 7.x is now out alongside Visual Studio 2017. This means that Sol v. 2.17.5 will be the last version of the code targeted at the older compilers. Newer code will be targeted at working with the following compilers and leveraging their features, possibly taking advantage of whatever C++17 features are made available by the compilers and standard libraries bundled by-default with them: +GCC 7.x is now out alongside Visual Studio 2017. This means that `sol2 release v2.18.0`_ is the current version of the code targeted at the older compilers not listed below. Newer code will be targeted at working with the following compilers and leveraging their features, possibly taking advantage of whatever C++17 features are made available by the compilers and standard libraries bundled by-default with them. + +``v2.18.0`` supports: * VC++ - Visual Studio 2017 - - Visual Studio 2015 (with latest updates) + - Visual Studio 2015 (Latest updates) * GCC (includes MinGW) - v7.x - v6.x - - v5.x + - v5.x + - v4.8+ * Clang - v4.x - v3.9.x - v3.8.x - v3.7.x + - v3.5.x - Note: this applies to XCode's Apple Clang as well, but that compiler packs its own deficiencies and problems as well +**This does not mean we are immediately abandoning older compilers.** We will update this page as relevant bugfixes are backported to the v2.x.x releases. Remember that sol2 is feature-complete: there is nothing more we can add to the library at this time with C++11/C++14 compiler support, so your code will be covered for a long time to come. + +Newer features will be targeted at the following compilers: + +* VC++ + - Visual Studio vNext + - Visual Studio 2017 +* GCC (includes MinGW) + - v7.x + - v6.x +* Clang + - v4.x + - v3.9.x + - v3.8.x + Note that Visual Studio's 2017 Community Edition is absolutely free now, and installs faster and easier than ever before. It also removes a lot of hacky work arounds and formally supports decltype SFINAE. MinGW's GCC version 7.x of the compiler fixes a long-standing derp in the header that swapped the endianness of utf16 and utf32 strings. Clang 3.4, 3.5 and 3.6 have many bugs we have run into when developing sol2 and that have negatively impacted users for a long time now. -We encourage all users to upgrade immediately. If you need old code, use `sol2 release v2.17.5`_: otherwise, always grab sol2's latest. +We encourage all users to upgrade immediately. If you need old code for some reason, use `sol2 release v2.18.0`_: otherwise, always grab sol2's latest. + + + +supported Lua version +--------------------- + +We support: + +* Lua 5.3+ +* Lua 5.2 +* Lua 5.1 +* LuaJIT 2.0.4+ +* LuaJIT 2.1.x-beta3+ + "compiler out of heap space" ---------------------------- @@ -47,10 +80,10 @@ binary sizes For individiauls who use :doc:`usertypes` a lot, they can find their compilation times increase. This is due to C++11 and C++14 not having very good facilities for handling template parameters and variadic template parameters. There are a few things in cutting-edge C++17 and C++Next that sol can use, but the problem is many people cannot work with the latest and greatest: therefore, we have to use older techniques that result in a fair amount of redundant function specializations that can be subject to the pickiness of the compiler's inlining and other such techniques. -what to do ----------- +compile speed improvemements +---------------------------- -Here are some notes on achieving better compile-times without sacrificing too much performance: +Here are some notes on achieving better compile times without sacrificing too much performance: * When you bind lots of usertypes, put them all in a *single* translation unit (one C++ file) so that it is not recompiled multiple times over, only to be discarded later by the linker. - Remember that the usertype binding ends up being serialized into the Lua state, so you never need them to appear in a header and cause that same compilation overhead for every compiled unit in your project. @@ -59,6 +92,7 @@ Here are some notes on achieving better compile-times without sacrificing too mu * For extremely large usertypes, consider using :doc:`simple_usertype`. - It performs much more work at runtime rather than compile-time, and should still give comparative performance (but it loses out in some cases for variable bindings or when you bind all functions to a usertype). * If you are developing a shared library, restrict your overall surface area by specifically and explicitly marking functions as visible and exported and leaving everything else as hidden or invisible by default +* For people who already have a tool that retrieves function signatures and arguments, it might be in your best interest to hook into that tool or generator and dump out the information once using sol2's lower-level abstractions. An `issue describing preliminary steps can be found here`_. next steps @@ -69,5 +103,6 @@ The next step for Sol from a developer standpoint is to formally make the librar Hopefully, as things progress, we move things forward. -.. _sol2 release v2.17.5: https://github.com/ThePhD/sol2/releases/tag/v2.17.5 +.. _sol2 release v2.18.0: https://github.com/ThePhD/sol2/releases/tag/v2.17.5 .. _OrfeasZ in this issue: https://github.com/ThePhD/sol2/issues/329#issuecomment-276824983 +.. _issue describing preliminary steps can be found here: https://github.com/ThePhD/sol2/issues/436#issuecomment-312021508 \ No newline at end of file diff --git a/docs/source/errors.rst b/docs/source/errors.rst index 5be185e1..c36c76e2 100644 --- a/docs/source/errors.rst +++ b/docs/source/errors.rst @@ -36,7 +36,7 @@ By default, Sol will add a ``default_at_panic`` handler. If exceptions are not t It is preferred if you catch an error that you log what happened, terminate the Lua VM as soon as possible, and then crash if your application cannot handle spinning up a new Lua state. Catching can be done, but you should understand the risks of what you're doing when you do it. For more information about catching exceptions, the potentials, not turning off exceptions and other tricks and caveats, read about :doc:`exceptions in Sol here`. -Lua is a C API first and foremost: exceptions bubbling out of it is essentially last-ditch, terminal behavior that the VM does not expect. You can see an example of handling a panic on the exceptions page :ref:`here`. +Lua is a C API first and foremost: exceptions bubbling out of it is essentially last-ditch, terminal behavior that the VM does not expect. You can see an example of handling a panic on the exceptions page :ref:`here`. This means that setting up a ``try { ... } catch (...) {}`` around an unprotected sol2 function or script call is **NOT** enough to keep the VM in a clean state. Lua does not understand exceptions and throwing them results in undefined behavior if they bubble through the C API once and then the state is used again. Please catch, and crash. Furthermore, it would be a great idea for you to use the safety features talked about :doc:`safety section`, especially for those related to functions. @@ -55,17 +55,7 @@ By default, :doc:`sol::function` assumes the code ran just fine an Protected Functions Are Not Catch All ------------------------------------- -Sometimes, some scripts load poorly. Even if you protect the function call, the actual file loading or file execution will be bad, in which case :doc:`sol::protected_function` will not save you. Make sure you register your own panic handler so you can catch errors, or follow the advice of the catch + crash behavior above. - -Raw Functions -------------- - -When you push a function into Lua using Sol using any methods and that function exactly matches the signature ``int( lua_State* );`` (and is a free function (e.g., not a member function pointer)), it will be treated as a *raw C function*. This means that the usual exception trampoline Sol wraps your other function calls in will not be present. You will be responsible for catching exceptions and handling them before they explode into the C API (and potentially destroy your code). Sol in all other cases adds an exception-handling trampoline that turns exceptions into Lua errors that can be caught by the above-mentioned protected functions and accessors. - -.. warning:: - - Do NOT assume that building Lua as C++ will allow you to throw directly from a raw function. If an exception is raised and it bubbles into the Lua framework, even if you compile as C++, Lua does not recognize exceptions other than the ones that it uses with ``lua_error``. In other words, it will return some completely bogus result, potentially leave your Lua stack thrashed, and the rest of your VM *can* be in a semi-trashed state. Please avoid this! - +Sometimes, some scripts load poorly. Even if you protect the function call, the actual file loading or file execution will be bad, in which case :doc:`sol::protected_function` will not save you. Make sure you register your own panic handler so you can catch errors, or follow the advice of the catch + crash behavior above. Remember that you can also bind your own functions and forego sol2's built-in protections for you own by binding a :ref:`raw lua_CFunction function` Iteration --------- diff --git a/docs/source/features.rst b/docs/source/features.rst index 4c2324e4..dde933f6 100644 --- a/docs/source/features.rst +++ b/docs/source/features.rst @@ -10,7 +10,7 @@ For the hard technical components of Lua and its ecosystem we support, here is t what Sol supports ----------------- -* Support for Lua 5.1, 5.2, and 5.3. We achieve this through our :doc:`compatibility` header. +* Support for Lua 5.1, 5.2, and 5.3+ and LuaJIT 2.0.4 + 2.1.x-beta3+. We achieve this through our :doc:`compatibility` header. * :doc:`Table` support: setting values, getting values of multiple (different) types - :doc:`Lazy evaluation` for nested/chained queries @@ -24,13 +24,12 @@ what Sol supports - Turns on safety when you want it: speed when you don't * Support for callables (functions, lambdas, member functions) - - Pull out any Lua function with :doc:`sol::function` - ``sol::function fx = table["socket_send"];`` - - Can also set callables into :doc:`operator[] proxies` - ``table["move_dude"] = engine::move_dude;`` + - Pull out any Lua function with :doc:`sol::function`: ``sol::function fx = table["socket_send"];`` + - Can also set callables into :doc:`operator[] proxies`: ``table["move_dude"] = &engine::move_dude;`` - Safety: use :doc:`sol::protected_function` to catch any kind of error + ANY kind: C++ exception or Lua erors are trapped and run through the optional ``error_handler`` variable - - *Advanced:* Overloading of a single function so you don't need to do boring typechecks + - *Advanced:* :doc:`overloading of a single function name` so you don't need to do boring typechecks + - *Advanced:* :doc:`efficient handling and well-documented` way of dealing with arguments * User-Defined Type (:doc:`sol::usertype` in the API) support: - Set member functions to be called diff --git a/docs/source/functions.rst b/docs/source/functions.rst new file mode 100644 index 00000000..d5c7425e --- /dev/null +++ b/docs/source/functions.rst @@ -0,0 +1,83 @@ +functions +========= +working with functions in sol2 +------------------------------ + + +There are a number of examples dealing with functions and how they can be bound to sol2: + +* For a quicker walkthrough that demonstrates almost everything, see `the examples`_ and the :doc:`the quick and dirty tutorial` +* For a full explanation, :doc:`read the tutorial` and consult the subjects below +* If you have bindings and set-ups that want to leverage the C API without sol2's interference, you can push a raw function, which has certain implications (noted :ref:`below`) +* You can work with **transparent arguments** that provide you with special information, such as + - :doc:`sol::variadic_args`, for handling variable number of arguments at runtime + - :doc:`sol::this_state`, for getting the current Lua state + - :doc:`sol::this_environment`, for potentially retrieving the current Lua environment +* :doc:`Overload function calls on a single name`, discriminating by argument number and type (first-come, first-serve overloading) +* Control serialization of arguments and return types with :doc:`sol::nested`, :doc:`sol::as_table`, :doc:`sol::as_args` and :doc:`sol::as_function` +* Set environments for Lua functions and scrips with :doc:`sol::environment` + + +.. _binding-callable-objects: + +working with callables/lambdas +------------------------------ + +.. note:: + + Function objects ``obj`` -- a struct with a ``return_type operator()( ... )`` member defined on them, like all C++ lambdas -- are not interpreted as functions when you use ``set`` for ``mytable.set( key, value )`` and ``state.create_table(_with)( ... )``. This only happens automagically with ``mytable[key] = obj``. To be explicit about wanting a struct to be interpreted as a function, use ``mytable.set_function( key, func_value );``. You can be explicit about wanting a function as well by using the :doc:`sol::as_function<../api/as_function>` call, which will wrap and identify your type as a function. + +.. _function-exception-handling: + +exception safety/handling +------------------------- + +All functions bound to sol2 set up an exception trampoline around the function (unless you are working with a :ref:`raw lua_CFunction you pushed yourself`). :doc:`protected_function` also has an error handler member and an exception trampoline around its internals, but it is not guaranteed safe if an exception bubbles outside of it. Catching that exception is not safe either: if an exception has exploded out from the sol2 API somehow, you must assume the VM is in some indeterminate and/or busted state. + +Please read the :doc:`error page` and :doc:`exception page` for more details about what to do with exceptions that explode out from the API. + + +.. _function-argument-handling: + +functions and argument passing +------------------------------ + +.. note:: + + All arguments are forwarded. Unlike :doc:`get/set/operator[] on sol::state` or :doc:`sol::table`, value semantics are not used here. It is forwarding reference semantics, which do not copy/move unless it is specifically done by the receiving functions / specifically done by the user. + + +.. note:: + + This also means that you should pass and receive arguments in certain ways to maximize efficiency. For example, ``sol::table``, ``sol::object``, ``sol::userdata`` and friends are cheap to copy, and should simply by taken as values. This includes primitive types like ``int`` and ``double``. However, C++ types -- if you do not want copies -- should be taken as ``const type&`` or ``type&``, to save on copies if it's important. Note that taking references from Lua also means you can modify the data inside of Lua directly, so be careful. Lua by default deals with things mostly by reference (save for primitive types). + + Please avoid taking special unique_usertype arguments, by either reference or value. In many cases, by-value does not work (e.g., with ``std::unique_ptr``) because many types are move-only and Lua has no concept of "move" semantics. By-reference is dangerous because sol2 will hand you a reference to the original data: but, any pointers stored in Lua can be invalidated if you call ``.reset()`` or similar on the core pointer. Please take a pointer (``T*``) if you anticipate ``nil``/``nullptr`` being passed to your function, or a reference (``const T&`` or ``T&``) if you do not. + + You can get even more speed out of ``sol::object`` style of types by taking a ``sol::stack_object`` (or ``sol::stack_...``, where ``...`` is ``userdata``, ``reference``, ``table``, etc.). These reference a stack position directly rather than cheaply/safely the internal Lua reference to make sure it can't be swept out from under you. Note that if you manipulate the stack out from under these objects, they may misbehave, so please do not blow up your Lua stack when working with these types. + + ``std::string`` (and ``std::wstring``) are special. Lua stores strings as ``const char*`` null-terminated strings. ``std::string`` will copy, so taking a ``std::string`` by value or by const reference still invokes a copy operation. You can take a ``const char*``, but that will mean you're exposed to what happens on the Lua stack (if you change it and start chopping off function arguments from it in your function calls and such, as warned about previously). + + +.. _function-argument-safety: + +function call safety +-------------------- + +You can have functions here and on usertypes check to definitely make sure that the types passed to C++ functions are what they're supposed to be by adding a ``#define SOL_CHECK_ARGUMENTS`` before including Sol, or passing it on the command line. Otherwise, for speed reasons, these checks are only used where absolutely necessary (like discriminating between :doc:`overloads`). See :doc:`safety<../safety>` for more information. + + +.. _raw-function-note: + +raw functions (``lua_CFunction``) +--------------------------------- + +When you push a function into Lua using Sol using any methods and that function exactly matches the signature ``int( lua_State* );``, it will be treated as a *raw C function* (a ``lua_CFunction``). This means that the usual exception trampoline Sol wraps your other function calls in will not be present. You will be responsible for catching exceptions and handling them before they explode into the C API (and potentially destroy your code). Sol in all other cases adds an exception-handling trampoline that turns exceptions into Lua errors that can be caught by the above-mentioned protected functions and accessors. + +Note that stateless lambdas can be converted to a function pointer, so stateless lambdas similar to the form ``[](lua_State*) -> int { ... }`` will also be pushed as raw functions. If you need to get the Lua state that is calling a function, use :doc:`sol::this_state`. + +.. warning:: + + Do NOT assume that building Lua as C++ will allow you to throw directly from a raw function. If an exception is raised and it bubbles into the Lua framework, even if you compile as C++, Lua does not recognize exceptions other than the ones that it uses with ``lua_error``. In other words, it will return some completely bogus result, potentially leave your Lua stack thrashed, and the rest of your VM *can* be in a semi-trashed state. Please avoid this! + + +.. _the examples: https://github.com/ThePhD/sol2/blob/develop/examples/functions.cpp diff --git a/docs/source/index.rst b/docs/source/index.rst index 9a2438a0..3a5b70f1 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -35,6 +35,7 @@ get going: errors compilation features + functions usertypes threading traits diff --git a/docs/source/tutorial/all-the-things.rst b/docs/source/tutorial/all-the-things.rst index aa2fc1b5..06863544 100644 --- a/docs/source/tutorial/all-the-things.rst +++ b/docs/source/tutorial/all-the-things.rst @@ -126,10 +126,10 @@ You can set/get everything. // string types lua["important_string"] = "woof woof"; - // non-recognized types is stored as userdata // is callable, therefore gets stored as a function lua["a_function"] = [](){ return 100; }; - + // otherwise, non-recognized types is stored as userdata + // make a table lua["some_table"] = lua.create_table_with("value", 24); diff --git a/docs/source/tutorial/functions.rst b/docs/source/tutorial/functions.rst index 3603c330..4802819c 100644 --- a/docs/source/tutorial/functions.rst +++ b/docs/source/tutorial/functions.rst @@ -162,9 +162,7 @@ This is useful for functions which can take multiple types and need to behave di As a side note, binding functions with default parameters does not magically bind multiple versions of the function to be called with the default parameters. You must instead use :doc:`sol::overload<../api/overload>`. -.. note:: - - Function object ``obj`` -- a struct with a ``return_type operator()( ... )`` member defined on them, like all C++ lambdas -- are not interpreted as functions when you use ``set`` for ``mytable.set( key, value )``. This only happens automagically with ``mytable[key] = obj``. To be explicit about wanting a struct to be interpreted as a function, use ``mytable.set_function( key, func_value );``. You can be explicit about wanting a function as well by using the :doc:`sol::as_function<../api/as_function>` call. +As a side note, please make sure to understand Make sure you understand the :ref:`implications of binding a lambda/callable struct in the various ways` and what it means for your code! Getting a function from Lua diff --git a/sol/container_traits.hpp b/sol/container_traits.hpp new file mode 100644 index 00000000..e5e843a6 --- /dev/null +++ b/sol/container_traits.hpp @@ -0,0 +1,32 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef SOL_CONTAINER_TRAITS_HPP +#define SOL_CONTAINER_TRAITS_HPP + +#include "stack.hpp" +#include + +namespace sol { + +} // sol + +#endif // SOL_CONTAINER_TRAITS_HPP diff --git a/test_functions.cpp b/test_functions.cpp index ebffb83b..eca8d244 100644 --- a/test_functions.cpp +++ b/test_functions.cpp @@ -1069,6 +1069,29 @@ TEST_CASE("functions/overloaded-variadic", "make sure variadics work to some deg REQUIRE(c == 2.2); } +TEST_CASE("functions/sectioning-variadic", "make sure variadics can bite off chunks of data") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.set_function("f", [](sol::variadic_args va) { + int r = 0; + sol::variadic_args shifted_va(va.lua_state(), 3); + for (auto v : shifted_va) { + int value = v; + r += value; + } + return r; + }); + + lua.script("x = f(1, 2, 3, 4)"); + lua.script("x2 = f(8, 200, 3, 4)"); + lua.script("x3 = f(1, 2, 3, 4, 5, 6)"); + + lua.script("print(x) assert(x == 7)"); + lua.script("print(x2) assert(x2 == 7)"); + lua.script("print(x3) assert(x3 == 18)"); +} + TEST_CASE("functions/set_function-already-wrapped", "setting a function returned from Lua code that is already wrapped into a sol::function or similar") { SECTION("test different types") { sol::state lua;