diff --git a/docs/source/api/api-top.rst b/docs/source/api/api-top.rst index 620d1135..82ea1a3d 100644 --- a/docs/source/api/api-top.rst +++ b/docs/source/api/api-top.rst @@ -23,9 +23,10 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo overload protect readonly + resolve + as_function property proxy - resolve stack optional state diff --git a/docs/source/api/as_function.rst b/docs/source/api/as_function.rst new file mode 100644 index 00000000..efe59b07 --- /dev/null +++ b/docs/source/api/as_function.rst @@ -0,0 +1,29 @@ +as_function +=========== +make sure a parameter is pushed as a function +--------------------------------------------- + +.. code-block:: cpp + + template , typename... Args> + function_argumants as_function ( Args&& ... ); + +This function serves the purpose of ensuring that a callable struct (like a lambda) can be passed to the ``set( key, value )`` calls on :ref:`sol::table` and be treated like a function binding instead of a userdata. It is recommended that one uses the :ref:`sol::table::set_function` call instead, but if for some reason one must use `set`, then `as_function` can help ensure a callable struct is handled like a lambda / callable, and not as just a userdata structure. + +.. code-block:: cpp + + struct callable { + int operator()( int a, bool b ) { + return a + b ? 10 : 20; + } + }; + + + sol::state lua; + // Binds struct as userdata + lua.set( "not_func", callable() ); + // Binds struct as function + lua.set( "func", sol::as_function( callable() ) ); + // equivalent: lua.set_function( "func", sol::as_function( callable() ) ); + +Note that if you actually want a userdata, but you want it to be callable, you simply need to create a :ref:`sol::table::new_usertype` and then bind the ``"__call"`` metamethod (or just use ``sol::meta_function::call`` :ref:`enumeration`). \ No newline at end of file diff --git a/docs/source/api/state.rst b/docs/source/api/state.rst index 03c30e37..909d61be 100644 --- a/docs/source/api/state.rst +++ b/docs/source/api/state.rst @@ -62,6 +62,7 @@ If your script returns a value, you can capture it from the returned :ref:`funct .. code-block:: cpp :caption: function: require / require_file + :name: state-require-function sol::object require(const std::string& key, lua_CFunction open_function, bool create_global = true); sol::object require_script(const std::string& key, const std::string& code, bool create_global = true); diff --git a/docs/source/api/table.rst b/docs/source/api/table.rst index 629d8c11..b5a94648 100644 --- a/docs/source/api/table.rst +++ b/docs/source/api/table.rst @@ -50,6 +50,7 @@ If the keys within nested queries try to traverse into a table that doesn't exis .. code-block:: cpp :caption: function: set / traversing set + :name: set-value template table& set(Args&&... args); @@ -63,6 +64,15 @@ These functions set items into the table. The first one (``set``) can set *mult Value semantics are applied to all set operations. If you do not ``std::ref( obj )`` or specifically make a pointer with ``std::addressof( obj )`` or ``&obj``, it will copy / move. This is different from how :doc:`sol::function` behaves with its call operator. +.. code-block:: cpp + :caption: function: set a function with the specified key into lua + :name: set-function + + template + state_view& set_function(Key&& key, Fx&& fx, [...]); + +Sets the desired function to the specified key value. Note that it also allows for passing a member function plus a member object or just a single member function: however, using a lambda is almost always better when you want to bind a member function + class instance to a single function call in Lua. + .. code-block:: cpp :caption: function: add @@ -159,14 +169,6 @@ A functional ``for_each`` loop that calls the desired function. The passed in fu Generates a :doc:`proxy` that is templated on the table type and the key type. Enables lookup of items and their implicit conversion to a desired type. -.. code-block:: cpp - :caption: function: set a function with the specified key into lua - - template - state_view& set_function(Key&& key, Fx&& fx, [...]); - -Sets the desired function to the specified key value. Note that it also allows for passing a member function plus a member object or just a single member function: however, using a lambda is almost always better when you want to bind a member function + class instance to a single function call in Lua. - .. code-block:: cpp :caption: function: create a table with defaults :name: table-create diff --git a/docs/source/api/unique_usertype_traits.rst b/docs/source/api/unique_usertype_traits.rst index e6101160..4e819330 100644 --- a/docs/source/api/unique_usertype_traits.rst +++ b/docs/source/api/unique_usertype_traits.rst @@ -39,4 +39,6 @@ A traits type for alerting the library that a certain type is to be pushed as a } } -This will allow the framework to properly handle ``boost::shared_ptr``, with ref-counting and all. The `type` is the type that lua and sol will interact with, and will allow you to pull out a non-owning reference / pointer to the data when you just ask for a plain `T*` or `T&` or `T` using the getter functions and properties of Sol. \ No newline at end of file +This will allow the framework to properly handle ``boost::shared_ptr``, with ref-counting and all. The `type` is the type that lua and sol will interact with, and will allow you to pull out a non-owning reference / pointer to the data when you just ask for a plain `T*` or `T&` or `T` using the getter functions and properties of Sol. + +Note that if ``is_null`` triggers, a ``nil`` value will be pushed into Sol. \ No newline at end of file diff --git a/docs/source/benchmarks.rst b/docs/source/benchmarks.rst index 912c0136..b7de9694 100644 --- a/docs/source/benchmarks.rst +++ b/docs/source/benchmarks.rst @@ -11,7 +11,7 @@ These are some informal and formal benchmarks done by both the developers of sol As of the writing of this documentation (July 29th, 2016), :doc:`Sol` (Sol2) seems to take the cake in most categories for speed! Below are some graphs from `lua-bench`_. You can read the benchmarking code there if you think something was done wrong, and submit a pull requests or comment on something to make sure that ThePhD is being honest about his work. All categories are the performance of things described at the top of the :doc:`feature table`. -Note that Sol here makes use of its more performant variants (see :doc:`c_call`), and ThePhD also does his best to make use of the most performant variants for other frameworks by disabling type checks where possible as well (Thanks to Liam Devine of OOLua for explaining how to turn off type checks in OOLua). +Note that Sol here makes use of its more performant variants (see :doc:`c_call`), and ThePhD also does his best to make use of the most performant variants for other frameworks by disabling type checks where possible as well (Thanks to Liam Devine of OOLua for explaining how to turn off type checks in OOLua). Bars go up to the average execution time. Lower is better. Reported times are for the desired operation run through `nonius`_ Results are sorted from top to bottom by best to worst. Note that there are error bars to show potential variance in performance: generally, same-sized errors bars plus very close average execution time implies no significant difference in speed, despite the vastly different abstraction techniques used. diff --git a/docs/source/tutorial/existing.rst b/docs/source/tutorial/existing.rst index 14fd8968..89a83f80 100644 --- a/docs/source/tutorial/existing.rst +++ b/docs/source/tutorial/existing.rst @@ -20,6 +20,8 @@ If you're already using lua and you just want to use ``sol`` in some places, you :doc:`sol::state_view<../api/state>` is exactly like ``sol::state``, but it doesn't manage the lifetime of a ``lua_State*``. Therefore, you get all the goodies that come with a ``sol::state`` without any of the ownership implications. Sol has no initialization components that need to deliberately remain alive for the duration of the program. It's entirely self-containing and uses lua's garbage collectors and various implementation techniques to require no state C++-side. After you do that, all of the power of `Sol` is available to you, and then some! +You may also want to call ``require`` and supply a string of a script file or something that returns an object that you set equal to something in C++. For that, you can use the :ref:`require functionality`. + Remember that Sol can be as lightweight as you want it: almost all of Sol's types take the ``lua_State*`` argument and then a second ``int index`` stack index argument, meaning you can use :doc:`tables<../api/table>`, :doc:`lua functions<../api/function>`, :doc:`coroutines<../api/coroutine>`, and other reference-derived objects that expose the proper constructor for your use. You can also set :doc:`usertypes<../api/usertype>` and other things you need without changing your entire architecture. -Note that you can also make non-standard pointer and reference types with custom reference counting and such also play nice with the system. See :doc:`unique_usertype_traits\<../api/unique_usertype_traits>` to see how! \ No newline at end of file +Note that you can also make non-standard pointer and reference types with custom reference counting and such also play nice with the system. See :doc:`unique_usertype_traits\<../api/unique_usertype_traits>` to see how! Custom types is also mentioned in the :doc:`customization tutorial`. \ No newline at end of file diff --git a/docs/source/tutorial/functions.rst b/docs/source/tutorial/functions.rst index 061df26c..0b38745e 100644 --- a/docs/source/tutorial/functions.rst +++ b/docs/source/tutorial/functions.rst @@ -291,7 +291,9 @@ You can also return mutiple items yourself from a C++-bound function. Here, we'r // c == "meow" -Note here that we use :doc:`sol::object<../api/object>` to transport through "any value" that can come from Lua. You can also use ``sol::make_object`` to create an object from some value, so that it can be returned into Lua as well. +Note here that we use :doc:`sol::object<../api/object>` to transport through "any value" that can come from Lua. You can also use ``sol::make_object`` to create an object from some value, so that it can be returned into Lua as well. + +Finally, note that there's a caveat if you use the regular :ref:`sol::table::set` function to set a lambda / callable C++ struct (see :doc:`here for more details<../api/as_function>`). This covers almost everything you need to know about Functions and how they interact with Sol. For some advanced tricks and neat things, check out :doc:`sol::this_state<../api/this_state>` and :doc:`sol::variadic_args<../api/variadic_args>`. The last stop in this tutorial is about :doc:`C++ types (usertypes) in Lua`! \ No newline at end of file diff --git a/docs/source/tutorial/getting-started.rst b/docs/source/tutorial/getting-started.rst index 1571f1ae..e1e6ce75 100644 --- a/docs/source/tutorial/getting-started.rst +++ b/docs/source/tutorial/getting-started.rst @@ -35,7 +35,7 @@ Using this simple command line: >>> g++ -std=c++14 test.cpp -llua -I"path/to/lua/include" -L"path/to/lua/lib" -Or using your favorite IDE / tool after setting up your include paths and library paths to lua according to the documentation of the Lua distribution you got. Remember your linked lua library (``-llua``) and include / library paths will depend on your OS, file system, Lua distribution and your installation / compilation method of your Lua distribution. +Or using your favorite IDE / tool after setting up your include paths and library paths to Lua according to the documentation of the Lua distribution you got. Remember your linked lua library (``-llua``) and include / library paths will depend on your OS, file system, Lua distribution and your installation / compilation method of your Lua distribution. .. note:: @@ -60,7 +60,7 @@ If this works, you're ready to start! The first line creates the ``lua_State`` a return 0; } -If you're interested in integrating Sol with a project that already uses some other library or Lua in the codebase, check out the :doc:`existing example` to see how to work with Sol when you add it to a project! +If you're interested in integrating Sol with a project that already uses some other library or Lua in the codebase, check out the :doc:`existing example` to see how to work with Sol when you add it to a project (the existing example covers ``require`` as well)! Next, let's start :doc:`reading/writing some variables` from Lua into C++, and vice-versa! diff --git a/docs/source/tutorial/ownership.rst b/docs/source/tutorial/ownership.rst index 06bb81b1..96eb350d 100644 --- a/docs/source/tutorial/ownership.rst +++ b/docs/source/tutorial/ownership.rst @@ -79,6 +79,13 @@ Sol can detect ``nullptr``, so if you happen to return it there won't be any dan return nullptr; }; + lua["my_func_2"] = [] () -> std::unique_ptr { + // default-constructs as a nullptr, + // gets pushed as nil to Lua + return std::unique_ptr(); + // same happens for std::shared_ptr + } + // Acceptable, it will set 'something' to nil // (and delete it on next GC if there's no more references) lua.set("something", nullptr); diff --git a/sol/function_types.hpp b/sol/function_types.hpp index c1606185..96f087e8 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -39,7 +39,7 @@ namespace sol { }; template , typename... Args> - function_arguments function_args(Args&&... args) { + function_arguments as_function(Args&&... args) { return function_arguments(std::forward(args)...); } diff --git a/sol/simple_usertype_metatable.hpp b/sol/simple_usertype_metatable.hpp index a163f7a4..eaa2f942 100644 --- a/sol/simple_usertype_metatable.hpp +++ b/sol/simple_usertype_metatable.hpp @@ -38,7 +38,7 @@ namespace sol { template >> = meta::enabler> void add(lua_State* L, N&& n, F&& f) { - registrations.emplace_back(make_object(L, std::forward(n)), make_object(L, function_args(std::forward(f)))); + registrations.emplace_back(make_object(L, std::forward(n)), make_object(L, as_function(std::forward(f)))); } template >> = meta::enabler> diff --git a/sol/table_core.hpp b/sol/table_core.hpp index 17aea60b..49c117d0 100644 --- a/sol/table_core.hpp +++ b/sol/table_core.hpp @@ -373,12 +373,12 @@ namespace sol { template>> = meta::enabler> void set_fx(types<>, Key&& key, Fx&& fx, Args&&... args) { - set(std::forward(key), function_args(std::forward(fx), std::forward(args)...)); + set(std::forward(key), as_function(std::forward(fx), std::forward(args)...)); } template void set_resolved_function(Key&& key, Args&&... args) { - set(std::forward(key), function_args>(std::forward(args)...)); + set(std::forward(key), as_function>(std::forward(args)...)); } public: diff --git a/tests.cpp b/tests.cpp index 0698dfe5..92d76b3d 100644 --- a/tests.cpp +++ b/tests.cpp @@ -335,7 +335,7 @@ TEST_CASE("state/require", "opening using a file") { struct open { static int open_func(lua_State* L) { sol::state_view lua = L; - return sol::stack::push(L, lua.create_table_with("modfunc", sol::function_args([]() { return 221; }))); + return sol::stack::push(L, lua.create_table_with("modfunc", sol::as_function([]() { return 221; }))); } }; @@ -356,7 +356,7 @@ TEST_CASE("state/multi-require", "make sure that requires transfers across hand- struct open { static int open_func(lua_State* L) { sol::state_view lua = L; - return sol::stack::push(L, lua.create_table_with("modfunc", sol::function_args([]() { return 221; }))); + return sol::stack::push(L, lua.create_table_with("modfunc", sol::as_function([]() { return 221; }))); } };