diff --git a/sol/function.hpp b/sol/function.hpp index f037fd07..1f60a257 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -65,9 +65,14 @@ public: void operator()(Args&&... args) { call<>(std::forward(args)...); } + + template + typename multi_return::type operator()(types, Args&&... args) { + return call(std::forward(args)...); + } template - auto call(Args&&... args) -> decltype(invoke(types(), sizeof...(Args))) { + typename multi_return::type call(Args&&... args) { push(); stack::push_args(state(), std::forward(args)...); return invoke(types(), sizeof...(Args)); diff --git a/sol/stack.hpp b/sol/stack.hpp index 617bc605..782bd98d 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -207,7 +207,7 @@ inline int push_user(lua_State* L, T& item) { namespace detail { template -inline void push(lua_State* L, indices, const T& tuplen) { +inline void push_tuple(lua_State* L, indices, T&& tuplen) { using swallow = char[ 1 + sizeof...(I) ]; swallow {'\0', (sol::stack::push(L, std::get(tuplen)), '\0')... }; } @@ -228,7 +228,12 @@ auto ltr_pop(lua_State* L, F&& f, types, Vs&&... vs) -> decltype( template inline void push(lua_State* L, const std::tuple& tuplen) { - detail::push(L, build_indices(), tuplen); + detail::push_tuple(L, build_reverse_indices(), tuplen); +} + +template +inline void push(lua_State* L, std::tuple&& tuplen) { + detail::push_tuple(L, build_reverse_indices(), std::move(tuplen)); } template @@ -236,9 +241,14 @@ inline auto pop_call(lua_State* L, TFx&& fx, types) -> decltype(detail: return detail::ltr_pop(L, std::forward(fx), types()); } -template -void push_args(lua_State* L, Args&&... args) { +void push_args(lua_State*) { + +} + +template +void push_args(lua_State* L, Arg&& arg, Args&&... args) { using swallow = char[]; + stack::push(L, std::forward(arg)); void(swallow{'\0', (stack::push(L, std::forward(args)), '\0')... }); } } // stack diff --git a/sol/table.hpp b/sol/table.hpp index 2496517a..b5c44a79 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -118,6 +118,11 @@ private: operator U() const { return t.get(key); } + + template + typename multi_return::type call(Args&&... args) { + return t.get(key)(types(), std::forward(args)...); + } }; template diff --git a/sol/traits.hpp b/sol/traits.hpp index 994dff81..c90a08c6 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -22,6 +22,7 @@ #ifndef SOL_TRAITS_HPP #define SOL_TRAITS_HPP +#include "tuple.hpp" #include namespace sol { @@ -62,6 +63,21 @@ struct is_function_impl { }; } // detail +template +struct multi_return { + typedef std::tuple type; +}; + +template +struct multi_return { + typedef T type; +}; + +template<> +struct multi_return<> : types<>{ + typedef void type; +}; + template using Bool = std::integral_constant; diff --git a/sol/tuple.hpp b/sol/tuple.hpp index 5a0ed438..31285b04 100644 --- a/sol/tuple.hpp +++ b/sol/tuple.hpp @@ -26,8 +26,23 @@ #include namespace sol { +template +struct reverse_tuple; + +template<> +struct reverse_tuple> { + using type = std::tuple<>; +}; + +template +struct reverse_tuple> { + using head = std::tuple; + using tail = typename reverse_tuple>::type; + using type = decltype(std::tuple_cat(std::declval(), std::declval())); +}; + template -struct indices {}; +struct indices { typedef indices type; }; template struct build_indices : build_indices {}; @@ -35,6 +50,12 @@ struct build_indices : build_indices {}; template struct build_indices<0, Ns...> : indices {}; +template +struct build_reverse_indices : build_reverse_indices {}; + +template +struct build_reverse_indices<0, Ns...> : indices {}; + template struct types : build_indices {}; diff --git a/sol/types.hpp b/sol/types.hpp index 44976ae6..e84682e0 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -113,6 +113,9 @@ template<> inline type type_of() { return type::boolean; } + +inline bool operator==(nil_t, nil_t) { return true; } +inline bool operator!=(nil_t, nil_t) { return false; } } // sol #endif // SOL_TYPES_HPP \ No newline at end of file diff --git a/tests.cpp b/tests.cpp index 4f23f6e4..5b020278 100644 --- a/tests.cpp +++ b/tests.cpp @@ -112,18 +112,38 @@ TEST_CASE("simple/callLambda", "A C++ lambda is exposed to lua and called") { } TEST_CASE("advanced/callLambdaReturns", "Checks for lambdas returning values") { + const static std::string lol = "lol", str = "str"; + const static std::tuple heh_tuple = std::make_tuple(1, 6.28f, 3.14, std::string("heh")); sol::state lua; REQUIRE_NOTHROW(lua.set_function("a", [ ] { return 42; })); + REQUIRE(lua["a"].call() == 42); + REQUIRE_NOTHROW(lua.set_function("b", [ ] { return 42u; })); + REQUIRE(lua["b"].call() == 42u); + REQUIRE_NOTHROW(lua.set_function("c", [ ] { return 3.14; })); + REQUIRE(lua["c"].call() == 3.14); + REQUIRE_NOTHROW(lua.set_function("d", [ ] { return 6.28f; })); + REQUIRE(lua["d"].call() == 6.28f); + REQUIRE_NOTHROW(lua.set_function("e", [ ] { return "lol"; })); + REQUIRE(lua["e"].call() == lol); + REQUIRE_NOTHROW(lua.set_function("f", [ ] { return true; })); + REQUIRE(lua["f"].call()); + REQUIRE_NOTHROW(lua.set_function("g", [ ] { return std::string("str"); })); + REQUIRE(lua["g"].call() == str); + REQUIRE_NOTHROW(lua.set_function("h", [ ] { })); + REQUIRE_NOTHROW(lua["h"].call()); + REQUIRE_NOTHROW(lua.set_function("i", [ ] { return sol::nil; })); - REQUIRE_NOTHROW(lua.set_function("j", [ ] { return std::make_tuple(1, 6.28f, 3.14, std::string( "heh" )); } )); + REQUIRE(lua["i"].call() == sol::nil); + REQUIRE_NOTHROW(lua.set_function("j", [ ] { return std::make_tuple(1, 6.28f, 3.14, std::string("heh")); })); + REQUIRE((lua["j"].call() == heh_tuple)); } TEST_CASE("advanced/callLambda2", "A C++ lambda is exposed to lua and called") { @@ -178,7 +198,7 @@ TEST_CASE("tables/functions_variables", "Check if tables and function calls work // l-value, can optomize auto lval = object(); lua.get("os").set_function("fun", &object::operator(), lval); - REQUIRE_NOTHROW((lua)); + REQUIRE_NOTHROW(run_script(lua)); // stateful lambda: non-convertible, unoptomizable int breakit = 50;