mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
customization points are now live
This commit is contained in:
parent
be946d415c
commit
045d9371df
|
@ -11,6 +11,26 @@ If you find that the higher level abstractions are not meeting your needs, you m
|
|||
|
||||
There are, however, a few :ref:`template customization points<extension_points>` that you may use for your purposes and a handful of potentially handy functions. These may help if you're trying to slim down the code you have to write, or if you want to make your types behave differently throughout the Sol stack. Note that overriding the defaults **can** throw out many of the safety guarantees Sol provides: therefore, modify the :ref:`extension points<extension_points>` at your own discretion.
|
||||
|
||||
structures
|
||||
----------
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: struct: record
|
||||
:name: stack-record
|
||||
|
||||
struct record {
|
||||
int last;
|
||||
int used;
|
||||
|
||||
void use(int count);
|
||||
};
|
||||
|
||||
This structure is for advanced usage with :ref:`stack::get<stack-get>` and :ref:`stack::check_get<stack-get>`. When overriding the customization points, it is important to call the ``use`` member function on this class with the amount of things you are pulling from the stack. ``used`` contains the total accumulation of items produced. ``last`` is the number of items gotten from the stack with the last operation (not necessarily popped from the stack). In all trivial cases for types, ``last == 1`` and ``used == 1`` after an operation; structures such as ``std::pair`` and ``std::tuple`` may pull more depending on the classes it contains.
|
||||
|
||||
When overriding the :doc:`customization points<../tutorial/customization>`, please note that this structure should enable you to push multiple return values and get multiple return values to the stack, and thus be able to seamlessly pack/unpack return values from Lua into a single C++ struct, and vice-versa. This functionality is only recommended for people who need to customize the library further than the basics. It is also a good way to add support for the type and propose it back to the original library so that others may benefit from your work.
|
||||
|
||||
Note that customizations can also be put up on a separate page here, if individuals decide to make in-depth custom ones for their framework or other places.
|
||||
|
||||
members
|
||||
-------
|
||||
|
||||
|
@ -20,9 +40,13 @@ members
|
|||
|
||||
template <typename T>
|
||||
auto get( lua_State* L, int index = -1 )
|
||||
template <typename T>
|
||||
auto get( lua_State* L, int index, record& tracking )
|
||||
|
||||
Retrieves the value of the object at ``index`` in the stack. The return type varies based on ``T``: with primitive types, it is usually ``T``: for all unrecognized ``T``, it is generally a ``T&`` or whatever the extension point :ref:`stack::getter\<T><getter>` implementation returns. The type ``T`` has top-level ``const`` qualifiers and reference modifiers removed before being forwarded to the extension point :ref:`stack::getter\<T><getter>` struct. ``stack::get`` will default to forwarding all arguments to the :ref:`stack::check_get<stack-check-get>` function with a handler of ``type_panic`` to strongly alert for errors, if you ask for the :doc:`safety<../safety>`.
|
||||
|
||||
`record`
|
||||
|
||||
You may also retrieve an :doc:`sol::optional\<T><optional>` from this as well, to have it attempt to not throw errors when performing the get and the type is not correct.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
@ -44,7 +68,7 @@ Checks if the object at ``index`` is of type ``T``. If it is not, it will call t
|
|||
template <typename T>
|
||||
auto check_get( lua_State* L, int index = -1 )
|
||||
template <typename T, typename Handler>
|
||||
auto check_get( lua_State* L, int index, Handler&& handler )
|
||||
auto check_get( lua_State* L, int index, Handler&& handler, record& tracking )
|
||||
|
||||
Retrieves the value of the object at ``index`` in the stack, but does so safely. It returns an ``optional<U>``, where ``U`` in this case is the return type deduced from ``stack::get<T>``. This allows a person to properly check if the type they're getting is what they actually want, and gracefully handle errors when working with the stack if they so choose to. You can define ``SOL_CHECK_ARGUMENTS`` to turn on additional :doc:`safety<../safety>`, in which ``stack::get`` will default to calling this version of the function with a handler of ``type_panic`` to strongly alert for errors and help you track bugs if you suspect something might be going wrong in your system.
|
||||
|
||||
|
@ -117,6 +141,10 @@ This struct is used for showing whether or not a :ref:`probing get_field<stack-p
|
|||
objects (extension points)
|
||||
--------------------------
|
||||
|
||||
You can customize the way Sol handles different structures and classes by following the information provided in the :doc:`adding your own types<../tutorial/customization>`.
|
||||
|
||||
Below is more extensive information for the curious.
|
||||
|
||||
The structs below are already overriden for a handful of types. If you try to mess with them for the types ``sol`` has already overriden them for, you're in for a world of thick template error traces and headaches. Overriding them for your own user defined types should be just fine, however.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
@ -125,7 +153,7 @@ The structs below are already overriden for a handful of types. If you try to me
|
|||
|
||||
template <typename T, typename = void>
|
||||
struct getter {
|
||||
static T get (int index = -1) {
|
||||
static T get (lua_State* L, int index, record& tracking) {
|
||||
// ...
|
||||
return // T, or something related to T.
|
||||
}
|
||||
|
@ -156,7 +184,7 @@ This is an SFINAE-friendly struct that is meant to expose static function ``push
|
|||
template <typename T, type expected = lua_type_of<T>, typename = void>
|
||||
struct checker {
|
||||
template <typename Handler>
|
||||
static bool check ( lua_State* L, int index, Handler&& handler ) {
|
||||
static bool check ( lua_State* L, int index, Handler&& handler, record& tracking ) {
|
||||
// if the object in the Lua stack at index is a T, return true
|
||||
if ( ... ) return true;
|
||||
// otherwise, call the handler function,
|
||||
|
@ -166,6 +194,6 @@ This is an SFINAE-friendly struct that is meant to expose static function ``push
|
|||
}
|
||||
};
|
||||
|
||||
This is an SFINAE-friendly struct that is meant to expose static function ``check`` that returns the number of things pushed onto the stack. The default implementation simply checks whether the expected type passed in through the template is equal to the type of the object at the specified index in the Lua stack. The default implementation for types which are considered ``userdata`` go through a myriad of checks to support checking if a type is *actually* of type ``T`` or if its the base class of what it actually stored as a userdata in that index. Down-casting from a base class to a mroe derived type is, unfortunately, impossible to do.
|
||||
This is an SFINAE-friendly struct that is meant to expose static function ``check`` that returns the number of things pushed onto the stack. The default implementation simply checks whether the expected type passed in through the template is equal to the type of the object at the specified index in the Lua stack. The default implementation for types which are considered ``userdata`` go through a myriad of checks to support checking if a type is *actually* of type ``T`` or if its the base class of what it actually stored as a userdata in that index. Down-casting from a base class to a more derived type is, unfortunately, impossible to do.
|
||||
|
||||
.. _lua_CFunction: http://www.Lua.org/manual/5.3/manual.html#lua_CFunction
|
104
docs/source/tutorial/customization.rst
Normal file
104
docs/source/tutorial/customization.rst
Normal file
|
@ -0,0 +1,104 @@
|
|||
adding your own types
|
||||
=====================
|
||||
|
||||
Sometimes, overriding Sol to make it handle certain ``struct``s and ``class``es as something other than just userdata is desirable. The way to do this is to take advantage of the 4 customization points for Sol. These are ``sol::lua_size<T>``, ``sol::stack::pusher<T, C>``, ``sol::stack::getter<T, C>``, ``sol::stack::checker<T, sol::type t, C>``.
|
||||
|
||||
The first thing to do is decide whether or not your type can be gotten from the stack, and whether or not it should also be pushed as arguments or such into Lua. If you need to retrieve it (as a return using one or multiple values from a Lua return), you should override but ``sol::stack::getter`` and ``sol::stack::checker``. If you need to push it into Lua at some point, then you'll want to override ``sol::stack::pusher``. For both cases, you need to override ``sol::lua_size``.
|
||||
|
||||
These are structures, so you'll override them using a technique C++ calls *class/struct specialization*. Below is an example of a struct that gets broken apart into 2 pieces when being pushed into Lua, and then pulled back into a struct when retrieved from Lua:
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: two_things.hpp
|
||||
:name: customization-overriding
|
||||
|
||||
#include <sol.hpp>
|
||||
|
||||
struct two_things {
|
||||
int a;
|
||||
bool b;
|
||||
};
|
||||
|
||||
namespace sol {
|
||||
|
||||
// First, the expected size
|
||||
// Specialization of a struct
|
||||
template <>
|
||||
struct lua_size<two_things> : std::integral_constant<int, 2> {};
|
||||
|
||||
// Now, specialize various stack structures
|
||||
namespace stack {
|
||||
|
||||
template <>
|
||||
struct checker<two_things> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
// Check first and second second index for being the proper types
|
||||
bool success = stack::check<int>(L, index, handler)
|
||||
&& stack::check<bool>(L, index + 1, handler);
|
||||
tracking.use(2);
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct getter<two_things> {
|
||||
static two_things get(lua_State* L, int index, record& tracking) {
|
||||
// Get the first element
|
||||
int a = stack::get<int>(L, index);
|
||||
// Get the second element,
|
||||
// in the +1 position from the first
|
||||
bool b = stack::get<bool>(L, index + 1);
|
||||
// we use 2 slots, each of the previous takes 1
|
||||
tracking.use(2);
|
||||
return two_things{ a, b };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<two_things> {
|
||||
static int push(lua_State* L, const two_things& things) {
|
||||
int amount = stack::push(L, things.a);
|
||||
amount += stack::push(L, things.b);
|
||||
// Return 2 things
|
||||
return amount;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
This is the base formula that you can follow to extend to your own classes. Using it in the rest of the framework should then be seamless:
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: customization: using it
|
||||
:name: customization-using
|
||||
|
||||
#include <sol.hpp>
|
||||
#include <two_things.hpp>
|
||||
|
||||
int main (int argc, char* argv[]) {
|
||||
|
||||
sol::state lua;
|
||||
|
||||
// Create a pass-through style of function
|
||||
lua.script("function f ( a, b ) return a, b end");
|
||||
|
||||
// get the function out of Lua
|
||||
sol::function f = lua["f"];
|
||||
|
||||
two_things things = f(two_things{24, true});
|
||||
// things.a == 24
|
||||
// things.b == true
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
And that's it!
|
||||
|
||||
A few things of note about the implementation: First, there's an auxiliary parameter of type :doc:`sol::stack::record<../api/stack>` for the getters and checkers. This keeps track of what the last complete operation performed. Since we retrieved 2 members, we use ``tracking.use(2);`` to indicate that we used 2 stack positions (one for ``bool``, one for ``int``). The second thing to note here is that we made sure to use the ``index`` parameter, and then proceeded to add 1 to it for the next one.
|
||||
|
||||
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.
|
||||
|
||||
You can read more about the structs themselves :ref:`over on the API page for stack<extension_points>`, and if there's something that goes wrong or you have anymore questions, please feel free to drop a line on the Github Issues page or send an e-mail!
|
|
@ -126,4 +126,4 @@ To do this, you bind things using the ``new_usertype`` and ``set_usertype`` meth
|
|||
|
||||
That script should run fine now, and you can observe and play around with the values. Even more stuff :doc:`you can do<../api/usertype>` is described elsewhere, like initializer functions (private constructors / destructors support), "static" functions callable with ``name.my_function( ... )``, and overloaded member functions.
|
||||
|
||||
This is a powerful way to allow reuse of C++ code from Lua beyond just registering functions, and should get you on your way to having more complex classes and data structures!
|
||||
This is a powerful way to allow reuse of C++ code from Lua beyond just registering functions, and should get you on your way to having more complex classes and data structures! In the case that you need more customization than just usertypes, however, you can customize Sol to behave more fit to your desires by using the desired :doc:`customization and extension structures<customization>`.
|
|
@ -16,3 +16,4 @@ Take some time to learn the framework with thse tutorials. But, if you need to g
|
|||
functions
|
||||
cxx-in-lua
|
||||
ownership
|
||||
customization
|
||||
|
|
|
@ -85,7 +85,6 @@ namespace sol {
|
|||
typedef lua_bind_traits<meta::unqualified_t<Fx>> traits;
|
||||
typedef meta::tuple_types<typename traits::return_type> return_types;
|
||||
typedef typename traits::free_args_list args_list;
|
||||
typedef typename args_list::indices args_indices;
|
||||
// compile-time eliminate any functions that we know ahead of time are of improper arity
|
||||
if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
|
||||
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
||||
|
@ -93,7 +92,8 @@ namespace sol {
|
|||
if (traits::free_arity != fxarity) {
|
||||
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::free_arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
||||
}
|
||||
if (!stack::stack_detail::check_types<true>().check(args_list(), args_indices(), L, start, no_panic)) {
|
||||
stack::record tracking{};
|
||||
if (!stack::stack_detail::check_types<true>{}.check(args_list(), L, start, no_panic, tracking)) {
|
||||
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
|
||||
}
|
||||
return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
|
||||
|
|
|
@ -40,13 +40,13 @@ namespace sol {
|
|||
|
||||
template<std::size_t... I, typename... Ret>
|
||||
auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) const {
|
||||
luacall(n, sizeof...(Ret));
|
||||
luacall(n, lua_size<std::tuple<Ret...>>::value);
|
||||
return stack::pop<std::tuple<Ret...>>(base_t::lua_state());
|
||||
}
|
||||
|
||||
template<std::size_t I, typename Ret>
|
||||
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) const {
|
||||
luacall(n, 1);
|
||||
luacall(n, lua_size<Ret>::value);
|
||||
return stack::pop<Ret>(base_t::lua_state());
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ namespace sol {
|
|||
typedef meta::tuple_types<typename fx_t::return_type> return_types;
|
||||
|
||||
template<typename... Args, typename... Ret>
|
||||
static std::function<Signature> get_std_func(types<Ret...>, types<Args...>, lua_State* L, int index = -1) {
|
||||
static std::function<Signature> get_std_func(types<Ret...>, types<Args...>, lua_State* L, int index) {
|
||||
sol::function f(L, index);
|
||||
auto fx = [f, L, index](Args&&... args) -> meta::return_type_t<Ret...> {
|
||||
return f.call<Ret...>(std::forward<Args>(args)...);
|
||||
|
@ -113,7 +113,7 @@ namespace sol {
|
|||
}
|
||||
|
||||
template<typename... FxArgs>
|
||||
static std::function<Signature> get_std_func(types<void>, types<FxArgs...>, lua_State* L, int index = -1) {
|
||||
static std::function<Signature> get_std_func(types<void>, types<FxArgs...>, lua_State* L, int index) {
|
||||
sol::function f(L, index);
|
||||
auto fx = [f, L, index](FxArgs&&... args) -> void {
|
||||
f(std::forward<FxArgs>(args)...);
|
||||
|
@ -122,11 +122,13 @@ namespace sol {
|
|||
}
|
||||
|
||||
template<typename... FxArgs>
|
||||
static std::function<Signature> get_std_func(types<>, types<FxArgs...> t, lua_State* L, int index = -1) {
|
||||
static std::function<Signature> get_std_func(types<>, types<FxArgs...> t, lua_State* L, int index) {
|
||||
return get_std_func(types<void>(), t, L, index);
|
||||
}
|
||||
|
||||
static std::function<Signature> get(lua_State* L, int index) {
|
||||
static std::function<Signature> get(lua_State* L, int index, record& tracking) {
|
||||
tracking.last = 1;
|
||||
tracking.used += 1;
|
||||
type t = type_of(L, index);
|
||||
if (t == type::none || t == type::nil) {
|
||||
return nullptr;
|
||||
|
|
|
@ -66,13 +66,26 @@ namespace sol {
|
|||
return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
|
||||
}
|
||||
|
||||
struct evaluator {
|
||||
template <typename Fx, typename... Args>
|
||||
static decltype(auto) eval(types<>, std::index_sequence<>, lua_State*, int, record&, Fx&& fx, Args&&... args) {
|
||||
return std::forward<Fx>(fx)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Fx, typename Arg, typename... Args, std::size_t I, std::size_t... Is, typename... FxArgs>
|
||||
static decltype(auto) eval(types<Arg, Args...>, std::index_sequence<I, Is...>, lua_State* L, int start, record& tracking, Fx&& fx, FxArgs&&... fxargs) {
|
||||
return eval(types<Args...>(), std::index_sequence<Is...>(), L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)..., stack_detail::unchecked_get<Arg>(L, start + tracking.used, tracking));
|
||||
}
|
||||
};
|
||||
|
||||
template <bool checkargs = default_check_arguments, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
|
||||
inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
|
||||
#ifndef _MSC_VER
|
||||
static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention.");
|
||||
#endif // This compiler make me so fucking sad
|
||||
check_types<checkargs>{}.check(ta, tai, L, start, type_panic);
|
||||
return fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I - meta::count_for_to_pack<I, is_transparent_argument, Args...>::value)...);
|
||||
multi_check<checkargs, Args...>(L, start, type_panic);
|
||||
record tracking{};
|
||||
return evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
|
||||
}
|
||||
|
||||
template <bool checkargs = default_check_arguments, std::size_t... I, typename... Args, typename Fx, typename... FxArgs>
|
||||
|
@ -80,8 +93,9 @@ namespace sol {
|
|||
#ifndef _MSC_VER
|
||||
static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention.");
|
||||
#endif // This compiler make me so fucking sad
|
||||
check_types<checkargs>{}.check(ta, tai, L, start, type_panic);
|
||||
fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I - meta::count_for_to_pack<I, is_transparent_argument, Args...>::value)...);
|
||||
multi_check<checkargs, Args...>(L, start, type_panic);
|
||||
record tracking{};
|
||||
evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
|
||||
}
|
||||
} // stack_detail
|
||||
|
||||
|
|
|
@ -50,7 +50,8 @@ namespace sol {
|
|||
template <type expected, int(*check_func)(lua_State*, int)>
|
||||
struct basic_check {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
tracking.use(1);
|
||||
bool success = check_func(L, index) == 1;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
|
@ -59,35 +60,13 @@ namespace sol {
|
|||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <bool b>
|
||||
struct check_types {
|
||||
template <std::size_t I0, std::size_t... I, typename T, typename... Args, typename Handler>
|
||||
static bool check(types<T, Args...>, std::index_sequence<I0, I...>, lua_State* L, int firstargument, Handler&& handler) {
|
||||
if (!stack::check<T>(L, firstargument + I0, handler))
|
||||
return false;
|
||||
return check(types<Args...>(), std::index_sequence<I...>(), L, firstargument - static_cast<int>(is_transparent_argument<meta::unqualified_t<T>>::value), std::forward<Handler>(handler));
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
static bool check(types<>, std::index_sequence<>, lua_State*, int, Handler&&) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct check_types<false> {
|
||||
template <std::size_t... I, typename... Args, typename Handler>
|
||||
static bool check(types<Args...>, std::index_sequence<I...>, lua_State*, int, Handler&&) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // stack_detail
|
||||
|
||||
template <typename T, type expected, typename>
|
||||
struct checker {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
tracking.use(1);
|
||||
const type indextype = type_of(L, index);
|
||||
bool success = expected == indextype;
|
||||
if (!success) {
|
||||
|
@ -98,19 +77,17 @@ namespace sol {
|
|||
}
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
struct checker<type, type::none, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State*, int, Handler&&) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <type expected, typename C>
|
||||
struct checker<nil_t, expected, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
bool success = lua_isnoneornil(L, index);
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
bool success = lua_isnil(L, index);
|
||||
if (success) {
|
||||
tracking.use(1);
|
||||
return success;
|
||||
}
|
||||
tracking.use(0);
|
||||
success = lua_isnone(L, index);
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, expected, type_of(L, index));
|
||||
|
@ -123,9 +100,10 @@ namespace sol {
|
|||
struct checker<nullopt_t, expected, C> : checker<nil_t> {};
|
||||
|
||||
template <typename C>
|
||||
struct checker<this_state, type::none, C> {
|
||||
struct checker<this_state, type::poly, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State*, int, Handler&&) {
|
||||
static bool check(lua_State*, int, Handler&&, record& tracking) {
|
||||
tracking.use(0);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -133,7 +111,17 @@ namespace sol {
|
|||
template <typename C>
|
||||
struct checker<variadic_args, type::poly, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State*, int, Handler&&) {
|
||||
static bool check(lua_State*, int, Handler&&, record& tracking) {
|
||||
tracking.use(0);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
struct checker<type, type::poly, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State*, int, Handler&&, record& tracking) {
|
||||
tracking.use(0);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -141,7 +129,8 @@ namespace sol {
|
|||
template <typename T, typename C>
|
||||
struct checker<T, type::poly, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
tracking.use(1);
|
||||
bool success = !lua_isnone(L, index);
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
|
@ -154,7 +143,8 @@ namespace sol {
|
|||
template <typename T, typename C>
|
||||
struct checker<T, type::lightuserdata, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
tracking.use(1);
|
||||
type t = type_of(L, index);
|
||||
bool success = t == type::userdata || t == type::lightuserdata;
|
||||
if (!success) {
|
||||
|
@ -168,7 +158,8 @@ namespace sol {
|
|||
template <typename C>
|
||||
struct checker<userdata_value, type::userdata, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
tracking.use(1);
|
||||
type t = type_of(L, index);
|
||||
bool success = t == type::userdata;
|
||||
if (!success) {
|
||||
|
@ -195,7 +186,8 @@ namespace sol {
|
|||
template <typename T, typename C>
|
||||
struct checker<T, type::function, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
tracking.use(1);
|
||||
type t = type_of(L, index);
|
||||
if (t == type::nil || t == type::none || t == type::function) {
|
||||
// allow for nil to be returned
|
||||
|
@ -228,7 +220,8 @@ namespace sol {
|
|||
template <typename T, typename C>
|
||||
struct checker<T, type::table, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
tracking.use(1);
|
||||
type t = type_of(L, index);
|
||||
if (t == type::table) {
|
||||
return true;
|
||||
|
@ -244,20 +237,22 @@ namespace sol {
|
|||
template <typename T, typename C>
|
||||
struct checker<T*, type::userdata, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
tracking.use(1);
|
||||
const type indextype = type_of(L, index);
|
||||
// Allow nil to be transformed to nullptr
|
||||
if (indextype == type::nil) {
|
||||
return true;
|
||||
}
|
||||
return checker<T, type::userdata, C>{}.check(types<T>(), L, indextype, index, std::forward<Handler>(handler));
|
||||
return checker<T, type::userdata, C>{}.check(types<T>(), L, indextype, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename C>
|
||||
struct checker<T, type::userdata, C> {
|
||||
template <typename U, typename Handler>
|
||||
static bool check(types<U>, lua_State* L, type indextype, int index, Handler&& handler) {
|
||||
static bool check(types<U>, lua_State* L, type indextype, int index, Handler&& handler, record& tracking) {
|
||||
tracking.use(1);
|
||||
if (indextype != type::userdata) {
|
||||
handler(L, index, type::userdata, indextype);
|
||||
return false;
|
||||
|
@ -291,56 +286,54 @@ namespace sol {
|
|||
}
|
||||
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
const type indextype = type_of(L, index);
|
||||
return check(types<T>(), L, indextype, index, std::forward<Handler>(handler));
|
||||
return check(types<T>(), L, indextype, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct checker<T, type::userdata, std::enable_if_t<is_unique_usertype<T>::value>> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
return checker<typename unique_usertype_traits<T>::type, type::userdata>{}.check(L, index, std::forward<Handler>(handler));
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return checker<typename unique_usertype_traits<T>::type, type::userdata>{}.check(L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename C>
|
||||
struct checker<std::reference_wrapper<T>, type::userdata, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
return checker<T, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler));
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return checker<T, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Args, typename C>
|
||||
struct checker<std::tuple<Args...>, type::poly, C> {
|
||||
template <std::size_t... I, typename Handler>
|
||||
static bool apply(std::index_sequence<I...> is, lua_State* L, int index, Handler&& handler) {
|
||||
index = index < 0 ? lua_absindex(L, index) - (sizeof...(I)-1) : index;
|
||||
return stack_detail::check_types<true>{}.check(types<Args...>(), is, L, index, handler);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
return apply(std::make_index_sequence<sizeof...(Args)>(), L, index, std::forward<Handler>(handler));
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename A, typename B, typename C>
|
||||
struct checker<std::pair<A, B>, type::poly, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
index = index < 0 ? lua_absindex(L, index) - 1 : index;
|
||||
return stack::check<A>(L, index, handler) && stack::check<B>(L, index + 1, handler);
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return stack::multi_check<A, B>(L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename C>
|
||||
struct checker<optional<T>, type::poly, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler) {
|
||||
return lua_isnoneornil(L, index) || stack::check<T>(L, index, std::forward<Handler>(handler));
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
type t = type_of(L, index);
|
||||
if (t == type::none) {
|
||||
tracking.use(0);
|
||||
return true;
|
||||
}
|
||||
return t == type::nil || stack::check<T>(L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
|
|
|
@ -31,35 +31,39 @@ namespace sol {
|
|||
namespace stack {
|
||||
template <typename T, typename>
|
||||
struct check_getter {
|
||||
typedef stack_detail::strip_t<T> U;
|
||||
typedef std::conditional_t<is_proxy_primitive<T>::value, U, U&> R;
|
||||
typedef decltype(stack_detail::unchecked_get<T>(nullptr, 0, std::declval<record&>())) R;
|
||||
|
||||
template <typename Handler>
|
||||
static optional<R> get(lua_State* L, int index, Handler&& handler) {
|
||||
if (!check<T>(L, index, std::forward<Handler>(handler)))
|
||||
static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
if (!check<T>(L, index, std::forward<Handler>(handler))) {
|
||||
tracking.use(static_cast<int>(!lua_isnone(L, index)));
|
||||
return nullopt;
|
||||
return stack_detail::unchecked_get<T>(L, index);
|
||||
}
|
||||
return stack_detail::unchecked_get<T>(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct check_getter<optional<T>> {
|
||||
template <typename Handler>
|
||||
static decltype(auto) get(lua_State* L, int index, Handler&&) {
|
||||
return check_get<T>(L, index, no_panic);
|
||||
static decltype(auto) get(lua_State* L, int index, Handler&&, record& tracking) {
|
||||
return check_get<T>(L, index, no_panic, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct check_getter<T, std::enable_if_t<std::is_integral<T>::value && lua_type_of<T>::value == type::number>> {
|
||||
template <typename Handler>
|
||||
static optional<T> get(lua_State* L, int index, Handler&& handler) {
|
||||
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
int isnum = 0;
|
||||
lua_Integer value = lua_tointegerx(L, index, &isnum);
|
||||
if (isnum == 0) {
|
||||
handler(L, index, type::number, type_of(L, index));
|
||||
type t = type_of(L, index);
|
||||
tracking.use(static_cast<int>(t != type::none));
|
||||
handler(L, index, type::number, t);
|
||||
return nullopt;
|
||||
}
|
||||
tracking.use(1);
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
};
|
||||
|
@ -67,13 +71,16 @@ namespace sol {
|
|||
template <typename T>
|
||||
struct check_getter<T, std::enable_if_t<std::is_enum<T>::value && !meta::any_same<T, meta_function, type>::value>> {
|
||||
template <typename Handler>
|
||||
static optional<T> get(lua_State* L, int index, Handler&& handler) {
|
||||
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
int isnum = 0;
|
||||
lua_Integer value = lua_tointegerx(L, index, &isnum);
|
||||
if (isnum == 0) {
|
||||
handler(L, index, type::number, type_of(L, index));
|
||||
type t = type_of(L, index);
|
||||
tracking.use(static_cast<int>(t != type::none));
|
||||
handler(L, index, type::number, t);
|
||||
return nullopt;
|
||||
}
|
||||
tracking.use(1);
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
};
|
||||
|
@ -81,21 +88,24 @@ namespace sol {
|
|||
template <typename T>
|
||||
struct check_getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
|
||||
template <typename Handler>
|
||||
static optional<T> get(lua_State* L, int index, Handler&& handler) {
|
||||
static optional<T> get(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
int isnum = 0;
|
||||
lua_Number value = lua_tonumberx(L, index, &isnum);
|
||||
if (isnum == 0) {
|
||||
handler(L, index, type::number, type_of(L, index));
|
||||
type t = type_of(L, index);
|
||||
tracking.use(static_cast<int>(t != type::none));
|
||||
handler(L, index, type::number, t);
|
||||
return nullopt;
|
||||
}
|
||||
tracking.use(1);
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct getter<optional<T>> {
|
||||
static decltype(auto) get(lua_State* L, int index) {
|
||||
return check_get<T>(L, index, no_panic);
|
||||
static decltype(auto) get(lua_State* L, int index, record& tracking) {
|
||||
return check_get<T>(L, index, no_panic, tracking);
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
|
|
|
@ -82,6 +82,17 @@ namespace sol {
|
|||
operator bool() const { return success; };
|
||||
};
|
||||
|
||||
struct record {
|
||||
int last;
|
||||
int used;
|
||||
|
||||
record() : last(), used() {}
|
||||
void use(int count) {
|
||||
last = count;
|
||||
used += count;
|
||||
}
|
||||
};
|
||||
|
||||
namespace stack_detail {
|
||||
template <typename T>
|
||||
struct strip {
|
||||
|
@ -108,8 +119,8 @@ namespace sol {
|
|||
false;
|
||||
#endif
|
||||
template<typename T>
|
||||
inline decltype(auto) unchecked_get(lua_State* L, int index = -1) {
|
||||
return getter<meta::unqualified_t<T>>{}.get(L, index);
|
||||
inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) {
|
||||
return getter<meta::unqualified_t<T>>{}.get(L, index, tracking);
|
||||
}
|
||||
} // stack_detail
|
||||
|
||||
|
@ -164,12 +175,18 @@ namespace sol {
|
|||
}
|
||||
|
||||
template <typename T, typename Handler>
|
||||
bool check(lua_State* L, int index, Handler&& handler) {
|
||||
bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
typedef meta::unqualified_t<T> Tu;
|
||||
checker<Tu> c;
|
||||
// VC++ has a bad warning here: shut it up
|
||||
(void)c;
|
||||
return c.check(L, index, std::forward<Handler>(handler));
|
||||
return c.check(L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <typename T, typename Handler>
|
||||
bool check(lua_State* L, int index, Handler&& handler) {
|
||||
record tracking{};
|
||||
return check<T>(L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -178,9 +195,15 @@ namespace sol {
|
|||
return check<T>(L, index, handler);
|
||||
}
|
||||
|
||||
template<typename T, typename Handler>
|
||||
inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return check_getter<meta::unqualified_t<T>>{}.get(L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template<typename T, typename Handler>
|
||||
inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler) {
|
||||
return check_getter<meta::unqualified_t<T>>{}.get(L, index, std::forward<Handler>(handler));
|
||||
record tracking{};
|
||||
return check_get<T>(L, index, handler, tracking);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -193,20 +216,20 @@ namespace sol {
|
|||
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
template <typename T>
|
||||
inline auto tagged_get(types<T>, lua_State* L, int index = -1) -> decltype(stack_detail::unchecked_get<T>(L, index)) {
|
||||
auto op = check_get<T>(L, index, type_panic);
|
||||
inline auto tagged_get(types<T>, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) {
|
||||
auto op = check_get<T>(L, index, type_panic, tracking);
|
||||
return *op;
|
||||
}
|
||||
#else
|
||||
template <typename T>
|
||||
inline decltype(auto) tagged_get(types<T>, lua_State* L, int index = -1) {
|
||||
return stack_detail::unchecked_get<T>(L, index);
|
||||
inline decltype(auto) tagged_get(types<T>, lua_State* L, int index, record& tracking) {
|
||||
return stack_detail::unchecked_get<T>(L, index, tracking);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline decltype(auto) tagged_get(types<optional<T>>, lua_State* L, int index = -1) {
|
||||
return stack_detail::unchecked_get<optional<T>>(L, index);
|
||||
inline decltype(auto) tagged_get(types<optional<T>>, lua_State* L, int index, record& tracking) {
|
||||
return stack_detail::unchecked_get<optional<T>>(L, index, tracking);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -218,11 +241,72 @@ namespace sol {
|
|||
return 0;
|
||||
}
|
||||
|
||||
template <bool b>
|
||||
struct check_types {
|
||||
template <typename T, typename... Args, typename Handler>
|
||||
static bool check(types<T, Args...>, lua_State* L, int firstargument, Handler&& handler, record& tracking) {
|
||||
if (!stack::check<T>(L, firstargument + tracking.used, handler, tracking))
|
||||
return false;
|
||||
return check(types<Args...>(), L, firstargument, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
static bool check(types<>, lua_State*, int, Handler&&, record&) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct check_types<false> {
|
||||
template <typename... Args, typename Handler>
|
||||
static bool check(types<Args...>, lua_State*, int, Handler&&, record&) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // stack_detail
|
||||
|
||||
template <bool b, typename... Args, typename Handler>
|
||||
bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return stack_detail::check_types<b>{}.check(types<meta::unqualified_t<Args>...>(), L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <bool b, typename... Args, typename Handler>
|
||||
bool multi_check(lua_State* L, int index, Handler&& handler) {
|
||||
record tracking{};
|
||||
return multi_check<b, Args...>(L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <bool b, typename... Args>
|
||||
bool multi_check(lua_State* L, int index) {
|
||||
auto handler = no_panic;
|
||||
return multi_check<b, Args...>(L, index, handler);
|
||||
}
|
||||
|
||||
template <typename... Args, typename Handler>
|
||||
bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return multi_check<true, Args...>(L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <typename... Args, typename Handler>
|
||||
bool multi_check(lua_State* L, int index, Handler&& handler) {
|
||||
return multi_check<true, Args...>(L, index, std::forward<Handler>(handler));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
bool multi_check(lua_State* L, int index) {
|
||||
return multi_check<true, Args...>(L, index);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline decltype(auto) get(lua_State* L, int index, record& tracking) {
|
||||
return stack_detail::tagged_get(types<T>(), L, index, tracking);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline decltype(auto) get(lua_State* L, int index = -1) {
|
||||
return stack_detail::tagged_get(types<T>(), L, index);
|
||||
record tracking{};
|
||||
return get<T>(L, index, tracking);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -36,98 +36,111 @@ namespace sol {
|
|||
|
||||
template<typename T, typename>
|
||||
struct getter {
|
||||
static T& get(lua_State* L, int index = -1) {
|
||||
return getter<T&>{}.get(L, index);
|
||||
static T& get(lua_State* L, int index, record& tracking) {
|
||||
return getter<T&>{}.get(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
|
||||
static T get(lua_State* L, int index = -1) {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return static_cast<T>(lua_tonumber(L, index));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T, std::enable_if_t<meta::all<std::is_integral<T>, std::is_signed<T>>::value>> {
|
||||
static T get(lua_State* L, int index = -1) {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return static_cast<T>(lua_tointeger(L, index));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T, std::enable_if_t<meta::all<std::is_integral<T>, std::is_unsigned<T>>::value>> {
|
||||
static T get(lua_State* L, int index = -1) {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return static_cast<T>(lua_tointeger(L, index));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T, std::enable_if_t<std::is_enum<T>::value>> {
|
||||
static T get(lua_State* L, int index = -1) {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return static_cast<T>(lua_tointegerx(L, index, nullptr));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> {
|
||||
static T get(lua_State* L, int index = -1) {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return T(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<userdata_value> {
|
||||
static userdata_value get(lua_State* L, int index = -1) {
|
||||
static userdata_value get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return userdata_value(lua_touserdata(L, index));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<lightuserdata_value> {
|
||||
static lightuserdata_value get(lua_State* L, int index = -1) {
|
||||
static lightuserdata_value get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return lightuserdata_value(lua_touserdata(L, index));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<light<T>> {
|
||||
static light<T> get(lua_State* L, int index = -1) {
|
||||
static light<T> get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return light<T>(static_cast<T*>(lua_touserdata(L, index)));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<user<T>> {
|
||||
static T& get(lua_State* L, int index = -1) {
|
||||
static T& get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return *static_cast<T*>(lua_touserdata(L, index));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<user<T*>> {
|
||||
static T* get(lua_State* L, int index = -1) {
|
||||
static T* get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return static_cast<T*>(lua_touserdata(L, index));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<type> {
|
||||
static type get(lua_State *L, int index) {
|
||||
static type get(lua_State *L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return static_cast<type>(lua_type(L, index));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<bool> {
|
||||
static bool get(lua_State* L, int index) {
|
||||
static bool get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return lua_toboolean(L, index) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<std::string> {
|
||||
static std::string get(lua_State* L, int index = -1) {
|
||||
static std::string get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
std::size_t len;
|
||||
auto str = lua_tolstring(L, index, &len);
|
||||
return{ str, len };
|
||||
|
@ -136,7 +149,8 @@ namespace sol {
|
|||
|
||||
template <>
|
||||
struct getter<string_detail::string_shim> {
|
||||
string_detail::string_shim get(lua_State* L, int index) {
|
||||
string_detail::string_shim get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
size_t len;
|
||||
const char* p = lua_tolstring(L, index, &len);
|
||||
return string_detail::string_shim(p, len);
|
||||
|
@ -145,15 +159,17 @@ namespace sol {
|
|||
|
||||
template<>
|
||||
struct getter<const char*> {
|
||||
static const char* get(lua_State* L, int index = -1) {
|
||||
static const char* get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return lua_tostring(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<meta_function> {
|
||||
static meta_function get(lua_State *L, int index) {
|
||||
const char* name = getter<const char*>{}.get(L, index);
|
||||
static meta_function get(lua_State *L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
const char* name = getter<const char*>{}.get(L, index, tracking);
|
||||
for (std::size_t i = 0; i < meta_function_names.size(); ++i)
|
||||
if (meta_function_names[i] == name)
|
||||
return static_cast<meta_function>(i);
|
||||
|
@ -163,7 +179,8 @@ namespace sol {
|
|||
|
||||
template<>
|
||||
struct getter<char> {
|
||||
static char get(lua_State* L, int index = -1) {
|
||||
static char get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
size_t len;
|
||||
auto str = lua_tolstring(L, index, &len);
|
||||
return len > 0 ? str[0] : '\0';
|
||||
|
@ -174,28 +191,32 @@ namespace sol {
|
|||
|
||||
template<>
|
||||
struct getter<std::wstring> {
|
||||
static std::wstring get(lua_State* L, int index = -1) {
|
||||
static std::wstring get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<std::u16string> {
|
||||
static std::u16string get(lua_State* L, int index = -1) {
|
||||
static std::u16string get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<std::u32string> {
|
||||
static std::u32string get(lua_State* L, int index = -1) {
|
||||
static std::u32string get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return{};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<wchar_t> {
|
||||
static wchar_t get(lua_State* L, int index = -1) {
|
||||
static wchar_t get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
auto str = getter<std::wstring>{}.get(L, index);
|
||||
return str.size() > 0 ? str[0] : '\0';
|
||||
}
|
||||
|
@ -203,7 +224,8 @@ namespace sol {
|
|||
|
||||
template<>
|
||||
struct getter<char16_t> {
|
||||
static char get(lua_State* L, int index = -1) {
|
||||
static char get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
auto str = getter<std::u16string>{}.get(L, index);
|
||||
return str.size() > 0 ? str[0] : '\0';
|
||||
}
|
||||
|
@ -211,7 +233,8 @@ namespace sol {
|
|||
|
||||
template<>
|
||||
struct getter<char32_t> {
|
||||
static char32_t get(lua_State* L, int index = -1) {
|
||||
static char32_t get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
auto str = getter<std::u32string>{}.get(L, index);
|
||||
return str.size() > 0 ? str[0] : '\0';
|
||||
}
|
||||
|
@ -221,49 +244,56 @@ namespace sol {
|
|||
|
||||
template<>
|
||||
struct getter<nil_t> {
|
||||
static nil_t get(lua_State*, int = -1) {
|
||||
static nil_t get(lua_State*, int, record& tracking) {
|
||||
tracking.use(1);
|
||||
return nil;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<std::nullptr_t> {
|
||||
static std::nullptr_t get(lua_State*, int = -1) {
|
||||
static std::nullptr_t get(lua_State*, int, record& tracking) {
|
||||
tracking.use(1);
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<nullopt_t> {
|
||||
static nullopt_t get(lua_State*, int = -1) {
|
||||
static nullopt_t get(lua_State*, int, record& tracking) {
|
||||
tracking.use(1);
|
||||
return nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<this_state> {
|
||||
static this_state get(lua_State* L, int = -1) {
|
||||
static this_state get(lua_State* L, int, record& tracking) {
|
||||
tracking.use(0);
|
||||
return this_state{ L };
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<lua_CFunction> {
|
||||
static lua_CFunction get(lua_State* L, int index = -1) {
|
||||
static lua_CFunction get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return lua_tocfunction(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<c_closure> {
|
||||
static c_closure get(lua_State* L, int index = -1) {
|
||||
static c_closure get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return c_closure(lua_tocfunction(L, index), -1);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct getter<error> {
|
||||
static error get(lua_State* L, int index = -1) {
|
||||
static error get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
size_t sz = 0;
|
||||
const char* err = lua_tolstring(L, index, &sz);
|
||||
if (err == nullptr) {
|
||||
|
@ -275,20 +305,22 @@ namespace sol {
|
|||
|
||||
template<>
|
||||
struct getter<void*> {
|
||||
static void* get(lua_State* L, int index = -1) {
|
||||
static void* get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return lua_touserdata(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T*> {
|
||||
static T* get_no_nil(lua_State* L, int index = -1) {
|
||||
static T* get_no_nil(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
void** pudata = static_cast<void**>(lua_touserdata(L, index));
|
||||
void* udata = *pudata;
|
||||
return get_no_nil_from(L, udata, index);
|
||||
return get_no_nil_from(L, udata, index, tracking);
|
||||
}
|
||||
|
||||
static T* get_no_nil_from(lua_State* L, void* udata, int index = -1) {
|
||||
static T* get_no_nil_from(lua_State* L, void* udata, int index, record&) {
|
||||
if (detail::has_derived<T>::value && luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) {
|
||||
void* basecastdata = lua_touserdata(L, -1);
|
||||
detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata;
|
||||
|
@ -300,25 +332,27 @@ namespace sol {
|
|||
return obj;
|
||||
}
|
||||
|
||||
static T* get(lua_State* L, int index = -1) {
|
||||
static T* get(lua_State* L, int index, record& tracking) {
|
||||
type t = type_of(L, index);
|
||||
if (t == type::nil)
|
||||
if (t == type::nil) {
|
||||
tracking.use(1);
|
||||
return nullptr;
|
||||
return get_no_nil(L, index);
|
||||
}
|
||||
return get_no_nil(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<non_null<T*>> {
|
||||
static T* get(lua_State* L, int index = -1) {
|
||||
return getter<T*>::get_no_nil(L, index);
|
||||
static T* get(lua_State* L, int index, record& tracking) {
|
||||
return getter<T*>::get_no_nil(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T&> {
|
||||
static T& get(lua_State* L, int index = -1) {
|
||||
return *getter<T*>::get_no_nil(L, index);
|
||||
static T& get(lua_State* L, int index, record& tracking) {
|
||||
return *getter<T*>::get_no_nil(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -327,7 +361,8 @@ namespace sol {
|
|||
typedef typename unique_usertype_traits<T>::type P;
|
||||
typedef typename unique_usertype_traits<T>::actual_type Real;
|
||||
|
||||
static Real& get(lua_State* L, int index = -1) {
|
||||
static Real& get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
P** pref = static_cast<P**>(lua_touserdata(L, index));
|
||||
detail::special_destruct_func* fx = static_cast<detail::special_destruct_func*>(static_cast<void*>(pref + 1));
|
||||
Real* mem = static_cast<Real*>(static_cast<void*>(fx + 1));
|
||||
|
@ -337,29 +372,27 @@ namespace sol {
|
|||
|
||||
template<typename T>
|
||||
struct getter<std::reference_wrapper<T>> {
|
||||
static T& get(lua_State* L, int index = -1) {
|
||||
return getter<T&>{}.get(L, index);
|
||||
static T& get(lua_State* L, int index, record& tracking) {
|
||||
return getter<T&>{}.get(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
struct getter<std::tuple<Args...>> {
|
||||
template <std::size_t... I>
|
||||
static decltype(auto) apply(std::index_sequence<I...>, lua_State* L, int index = -1) {
|
||||
index = index < 0 ? lua_absindex(L, index) - (sizeof...(I)-1) : index;
|
||||
return std::tuple<decltype(stack::get<Args>(L, index + I))...>(stack::get<Args>(L, index + I)...);
|
||||
static decltype(auto) apply(std::index_sequence<I...>, lua_State* L, int index, record& tracking) {
|
||||
return std::tuple<decltype(stack::get<Args>(L, index))...>{stack::get<Args>(L, index + tracking.used, tracking)...};
|
||||
}
|
||||
|
||||
static decltype(auto) get(lua_State* L, int index = -1) {
|
||||
return apply(std::make_index_sequence<sizeof...(Args)>(), L, index);
|
||||
static decltype(auto) get(lua_State* L, int index, record& tracking) {
|
||||
return apply(std::make_index_sequence<sizeof...(Args)>(), L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename A, typename B>
|
||||
struct getter<std::pair<A, B>> {
|
||||
static decltype(auto) get(lua_State* L, int index = -1) {
|
||||
index = index < 0 ? lua_absindex(L, index) - 1 : index;
|
||||
return std::pair<decltype(stack::get<A>(L, index)), decltype(stack::get<B>(L, index))>(stack::get<A>(L, index), stack::get<B>(L, index + 1));
|
||||
static decltype(auto) get(lua_State* L, int index, record& tracking) {
|
||||
return std::pair<decltype(stack::get<A>(L, index)), decltype(stack::get<B>(L, index))>{stack::get<A>(L, index, tracking), stack::get<B>(L, index + tracking.used, tracking)};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -32,26 +32,9 @@ namespace sol {
|
|||
template <typename T, typename>
|
||||
struct popper {
|
||||
inline static decltype(auto) pop(lua_State* L) {
|
||||
decltype(auto) r = get<T>(L);
|
||||
lua_pop(L, 1);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
struct popper<std::tuple<Args...>> {
|
||||
inline static decltype(auto) pop(lua_State* L) {
|
||||
decltype(auto) r = get<std::tuple<Args...>>(L);
|
||||
lua_pop(L, static_cast<int>(sizeof...(Args)));
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
struct popper<std::pair<A, B>> {
|
||||
inline static decltype(auto) pop(lua_State* L) {
|
||||
decltype(auto) r = get<std::pair<A, B>>(L);
|
||||
lua_pop(L, 2);
|
||||
record tracking{};
|
||||
decltype(auto) r = get<T>(L, -lua_size<T>::value, tracking);
|
||||
lua_pop(L, tracking.used);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -77,6 +77,23 @@ namespace sol {
|
|||
};
|
||||
} // stack
|
||||
|
||||
namespace detail {
|
||||
template <>
|
||||
struct is_speshul<function_result> : std::true_type {};
|
||||
template <>
|
||||
struct is_speshul<protected_function_result> : std::true_type {};
|
||||
|
||||
template <std::size_t I, typename... Args, typename T>
|
||||
stack_proxy get(types<Args...>, index_value<0>, index_value<I>, const T& fr) {
|
||||
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t N, typename Arg, typename... Args, typename T, meta::enable<meta::boolean<(N > 0)>> = meta::enabler>
|
||||
stack_proxy get(types<Arg, Args...>, index_value<N>, index_value<I>, const T& fr) {
|
||||
return get(types<Args...>(), index_value<N - 1>(), index_value<I + lua_size<Arg>::value>(), fr);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
struct tie_size<function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
|
||||
|
||||
|
@ -85,6 +102,11 @@ namespace sol {
|
|||
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
|
||||
}
|
||||
|
||||
template <std::size_t I, typename... Args>
|
||||
stack_proxy get(types<Args...> t, const function_result& fr) {
|
||||
return detail::get(t, index_value<I>(), index_value<0>(), fr);
|
||||
}
|
||||
|
||||
template <>
|
||||
struct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
|
||||
|
||||
|
@ -92,6 +114,11 @@ namespace sol {
|
|||
stack_proxy get(const protected_function_result& fr) {
|
||||
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
|
||||
}
|
||||
|
||||
template <std::size_t I, typename... Args>
|
||||
stack_proxy get(types<Args...> t, const protected_function_result& fr) {
|
||||
return detail::get(t, index_value<I>(), index_value<0>(), fr);
|
||||
}
|
||||
} // sol
|
||||
|
||||
#endif // SOL_STACK_PROXY_HPP
|
||||
|
|
25
sol/tie.hpp
25
sol/tie.hpp
|
@ -26,6 +26,11 @@
|
|||
|
||||
namespace sol {
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
struct is_speshul : std::false_type {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct tie_size : std::tuple_size<T> {};
|
||||
|
||||
|
@ -48,15 +53,23 @@ namespace sol {
|
|||
typedef tie_size<std::tuple<Tn...>> tie_size;
|
||||
typedef std::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size;
|
||||
typedef std::make_index_sequence<indices_size::value> indices;
|
||||
set(indices(), std::forward<T>(target));
|
||||
set_extra(detail::is_speshul<meta::unqualified_t<T>>(), indices(), std::forward<T>(target));
|
||||
}
|
||||
|
||||
template <std::size_t... I, typename T>
|
||||
void set(std::index_sequence<I...>, T&& target) {
|
||||
void set_extra(std::true_type, std::index_sequence<I...>, T&& target) {
|
||||
using std::get;
|
||||
(void)detail::swallow{ 0,
|
||||
(get<I>(*this) = get<I>(target), 0)...
|
||||
, 0 };
|
||||
(get<I>(*this) = get<I>(types<Tn...>(), target), 0)...
|
||||
, 0 };
|
||||
}
|
||||
|
||||
template <std::size_t... I, typename T>
|
||||
void set_extra(std::false_type, std::index_sequence<I...>, T&& target) {
|
||||
using std::get;
|
||||
(void)detail::swallow{ 0,
|
||||
(get<I>(*this) = get<I>(target), 0)...
|
||||
, 0 };
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -64,8 +77,8 @@ namespace sol {
|
|||
|
||||
template <typename T>
|
||||
tie_t& operator= (T&& value) {
|
||||
typedef is_tieable<meta::unqualified_t<T>> bondable;
|
||||
set(bondable(), std::forward<T>(value));
|
||||
typedef is_tieable<meta::unqualified_t<T>> tieable;
|
||||
set(tieable(), std::forward<T>(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -515,6 +515,9 @@ namespace sol {
|
|||
template <>
|
||||
struct lua_type_of<nullopt_t> : std::integral_constant<type, type::nil> { };
|
||||
|
||||
template <>
|
||||
struct lua_type_of<std::nullptr_t> : std::integral_constant<type, type::nil> { };
|
||||
|
||||
template <>
|
||||
struct lua_type_of<sol::error> : std::integral_constant<type, type::string> { };
|
||||
|
||||
|
@ -581,6 +584,12 @@ namespace sol {
|
|||
template <>
|
||||
struct lua_type_of<variadic_args> : std::integral_constant<type, type::poly> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<this_state> : std::integral_constant<type, type::poly> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<type> : std::integral_constant<type, type::poly> {};
|
||||
|
||||
template <typename T>
|
||||
struct lua_type_of<T*> : std::integral_constant<type, type::userdata> {};
|
||||
|
||||
|
@ -593,12 +602,6 @@ namespace sol {
|
|||
template <>
|
||||
struct lua_type_of<meta_function> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<type> : std::integral_constant<type, type::none> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<this_state> : std::integral_constant<type, type::none> {};
|
||||
|
||||
template <typename T>
|
||||
struct lua_type_of<T, std::enable_if_t<
|
||||
meta::all<
|
||||
|
@ -609,14 +612,30 @@ namespace sol {
|
|||
>>
|
||||
>::value
|
||||
>> : std::integral_constant<type, type::table> {};
|
||||
|
||||
template <typename C, C v, template <typename...> class V, typename... Args>
|
||||
struct accumulate : std::integral_constant<C, v> {};
|
||||
|
||||
template <typename C, C v, template <typename...> class V, typename T, typename... Args>
|
||||
struct accumulate<C, v, V, T, Args...> : accumulate<C, v + V<T>::value, V, Args...> {};
|
||||
} // detail
|
||||
|
||||
template <typename T>
|
||||
struct lua_type_of : detail::lua_type_of<T> {};
|
||||
|
||||
template <typename T>
|
||||
struct lua_size : std::integral_constant<int, 1> { };
|
||||
|
||||
template <typename A, typename B>
|
||||
struct lua_size<std::pair<A, B>> : std::integral_constant<int, lua_size<A>::value + lua_size<B>::value> { };
|
||||
|
||||
template <typename... Args>
|
||||
struct lua_size<std::tuple<Args...>> : std::integral_constant<int, detail::accumulate<int, 0, lua_size, Args...>::value> { };
|
||||
|
||||
template <typename T>
|
||||
struct is_lua_primitive : std::integral_constant<bool,
|
||||
type::userdata != lua_type_of<meta::unqualified_t<T>>::value
|
||||
|| (lua_size<T>::value > 1)
|
||||
|| std::is_base_of<reference, meta::unqualified_t<T>>::value
|
||||
|| std::is_base_of<stack_reference, meta::unqualified_t<T>>::value
|
||||
|| meta::is_specialization_of<std::tuple, meta::unqualified_t<T>>::value
|
||||
|
|
|
@ -218,7 +218,8 @@ namespace sol {
|
|||
namespace stack {
|
||||
template <>
|
||||
struct getter<variadic_args> {
|
||||
static variadic_args get(lua_State* L, int index = -1) {
|
||||
static variadic_args get(lua_State* L, int index, record& tracking) {
|
||||
tracking.last = 0;
|
||||
return variadic_args(L, index);
|
||||
}
|
||||
};
|
||||
|
|
83
test_customizations.cpp
Normal file
83
test_customizations.cpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
#define SOL_CHECK_ARGUMENTS
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <sol.hpp>
|
||||
|
||||
struct two_things {
|
||||
int a;
|
||||
bool b;
|
||||
};
|
||||
|
||||
namespace sol {
|
||||
|
||||
// First, the expected size
|
||||
// Specialization of a struct
|
||||
template <>
|
||||
struct lua_size<two_things> : std::integral_constant<int, 2> {};
|
||||
|
||||
// Now, specialize various stack structures
|
||||
namespace stack {
|
||||
|
||||
template <>
|
||||
struct checker<two_things> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
// Check first and second second index for being the proper types
|
||||
bool success = stack::check<int>(L, index, handler)
|
||||
&& stack::check<bool>(L, index + 1, handler);
|
||||
tracking.use(2);
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct getter<two_things> {
|
||||
static two_things get(lua_State* L, int index, record& tracking) {
|
||||
// Get the first element
|
||||
int a = stack::get<int>(L, index);
|
||||
// Get the second element,
|
||||
// in the +1 position from the first
|
||||
bool b = stack::get<bool>(L, index + 1);
|
||||
// we use 2 slots, each of the previous takes 1
|
||||
tracking.use(2);
|
||||
return two_things{ a, b };
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<two_things> {
|
||||
static int push(lua_State* L, const two_things& things) {
|
||||
int amount = stack::push(L, things.a);
|
||||
amount += stack::push(L, things.b);
|
||||
// Return 2 things
|
||||
return amount;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("customization/split-struct", "using the newly documented customization points to handle different kinds of classes") {
|
||||
sol::state lua;
|
||||
|
||||
// Create a pass-through style of function
|
||||
lua.script("function f ( a, b, c ) return a + c, b end");
|
||||
lua.set_function("g", [](int a, bool b, int c, double d) {
|
||||
return std::make_tuple(a + c, b, d + 2.5);
|
||||
});
|
||||
|
||||
// get the function out of Lua
|
||||
sol::function f = lua["f"];
|
||||
sol::function g = lua["g"];
|
||||
|
||||
two_things thingsf = f(two_things{ 24, true }, 1);
|
||||
two_things thingsg;
|
||||
double d;
|
||||
sol::tie( thingsg, d ) = g(two_things{ 25, false }, 2, 34.0);
|
||||
REQUIRE(thingsf.a == 25);
|
||||
REQUIRE(thingsf.b);
|
||||
|
||||
REQUIRE(thingsg.a == 27);
|
||||
REQUIRE_FALSE(thingsg.b);
|
||||
REQUIRE(d == 36.5);
|
||||
}
|
|
@ -500,7 +500,8 @@ TEST_CASE("usertype/nonmember-functions", "let users set non-member functions th
|
|||
"print(tostring(t))\n"
|
||||
"t:gief()\n"
|
||||
"t:gief_stuff(20)\n"));
|
||||
REQUIRE((lua.get<giver>("t").a == 20));
|
||||
giver& g = lua.get<giver>("t");
|
||||
REQUIRE(g.a == 20);
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/unique-shared-ptr", "manage the conversion and use of unique and shared pointers ('unique usertypes')") {
|
||||
|
|
Loading…
Reference in New Issue
Block a user