diff --git a/sol/function.hpp b/sol/function.hpp index a770d08c..1748a0d9 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -23,12 +23,10 @@ #define SOL_FUNCTION_HPP #include "reference.hpp" -#include "tuple.hpp" #include "stack.hpp" -#include "function_types.hpp" -#include "usertype_traits.hpp" #include "resolve.hpp" #include "function_result.hpp" +#include "function_types.hpp" #include #include #include @@ -99,138 +97,6 @@ public: } }; -class protected_function : public reference { -private: - static reference& handler_storage() { - static sol::reference h; - return h; - } - -public: - static const reference& get_default_handler () { - return handler_storage(); - } - - static void set_default_handler( reference& ref ) { - handler_storage() = ref; - } - -private: - struct handler { - const reference& target; - int stackindex; - handler(const reference& target) : target(target), stackindex(0) { - if (target.valid()) { - stackindex = lua_gettop(target.lua_state()) + 1; - target.push(); - } - } - ~handler() { - if (stackindex > 0) { - lua_remove(target.lua_state(), stackindex); - } - } - }; - - int luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, handler& h) const { - return lua_pcallk(lua_state(), static_cast(argcount), static_cast(resultcount), h.stackindex, 0, nullptr); - } - - template - auto invoke(types, std::index_sequence, std::ptrdiff_t n, handler& h) const { - luacall(n, sizeof...(Ret), h); - int stacksize = lua_gettop(lua_state()); - int firstreturn = std::max(0, stacksize - static_cast(sizeof...(Ret)) + 1); - auto r = stack::get>(lua_state(), firstreturn); - lua_pop(lua_state(), static_cast(sizeof...(Ret))); - return r; - } - - template - Ret invoke(types, std::index_sequence, std::ptrdiff_t n, handler& h) const { - luacall(n, 1, h); - return stack::pop(lua_state()); - } - - template - void invoke(types, std::index_sequence, std::ptrdiff_t n, handler& h) const { - luacall(n, 0, h); - } - - protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, handler& h) const { - bool handlerpushed = error_handler.valid(); - int stacksize = lua_gettop(lua_state()); - int firstreturn = std::max(1, stacksize - static_cast(n) - 1); - int returncount = 0; - call_status code = call_status::ok; -#ifndef SOL_NO_EXCEPTIONS - auto onexcept = [&](const char* error) { - h.stackindex = 0; - if (h.target.valid()) { - h.target.push(); - stack::push(lua_state(), error); - lua_call(lua_state(), 1, 1); - } - else { - stack::push(lua_state(), error); - } - }; - try { -#endif // No Exceptions - code = static_cast(luacall(n, LUA_MULTRET, h)); - int poststacksize = lua_gettop(lua_state()); - returncount = poststacksize - firstreturn; -#ifndef SOL_NO_EXCEPTIONS - } - // Handle C++ errors thrown from C++ functions bound inside of lua - catch (const char* error) { - onexcept(error); - firstreturn = lua_gettop(lua_state()); - return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); - } - catch (const std::exception& error) { - onexcept(error.what()); - firstreturn = lua_gettop(lua_state()); - return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); - } - catch (...) { - throw; - } -#endif // No Exceptions - return protected_function_result(lua_state(), firstreturn + ( handlerpushed ? 0 : 1 ), returncount, returncount, code); - } - -public: - sol::reference error_handler; - - protected_function() = default; - protected_function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) { - type_assert(L, index, type::function); - } - protected_function(const protected_function&) = default; - protected_function& operator=(const protected_function&) = default; - protected_function( protected_function&& ) = default; - protected_function& operator=( protected_function&& ) = default; - - template - protected_function_result operator()(Args&&... args) const { - return call<>(std::forward(args)...); - } - - template - decltype(auto) operator()(types, Args&&... args) const { - return call(std::forward(args)...); - } - - template - decltype(auto) call(Args&&... args) const { - handler h(error_handler); - push(); - int pushcount = stack::push_args(lua_state(), std::forward(args)...); - return invoke(types(), std::index_sequence_for(), pushcount, h); - } -}; - namespace stack { template struct pusher> { diff --git a/sol/function_result.hpp b/sol/function_result.hpp index 6734dbe8..e1e5cf6d 100644 --- a/sol/function_result.hpp +++ b/sol/function_result.hpp @@ -71,62 +71,6 @@ public: lua_pop(L, returncount); } }; - -struct protected_function_result : public proxy_base { -private: - lua_State* L; - int index; - int returncount; - int popcount; - call_status error; - -public: - protected_function_result() = default; - protected_function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_status error = call_status::ok): L(L), index(index), returncount(returncount), popcount(popcount), error(error) { - - } - protected_function_result(const protected_function_result&) = default; - protected_function_result& operator=(const protected_function_result&) = default; - protected_function_result(protected_function_result&& o) : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), error(o.error) { - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.error = call_status::runtime; - } - protected_function_result& operator=(protected_function_result&& o) { - L = o.L; - index = o.index; - returncount = o.returncount; - popcount = o.popcount; - error = o.error; - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.error = call_status::runtime; - return *this; - } - - bool valid() const { - return error == call_status::ok; - } - - template - T get() const { - return stack::get(L, index); - } - - ~protected_function_result() { - stack::remove(L, index, popcount); - } -}; } // sol #endif // SOL_FUNCTION_RESULT_HPP diff --git a/sol/object.hpp b/sol/object.hpp index 60dafe3d..034cb03e 100644 --- a/sol/object.hpp +++ b/sol/object.hpp @@ -25,6 +25,7 @@ #include "reference.hpp" #include "stack.hpp" #include "function.hpp" +#include "protected_function.hpp" namespace sol { class object : public reference { diff --git a/sol/protected_function.hpp b/sol/protected_function.hpp new file mode 100644 index 00000000..b9eda3a2 --- /dev/null +++ b/sol/protected_function.hpp @@ -0,0 +1,164 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2016 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_PROTECTED_FUNCTION_HPP +#define SOL_PROTECTED_FUNCTION_HPP + +#include "reference.hpp" +#include "stack.hpp" +#include "protected_function_result.hpp" +#include + +namespace sol { +class protected_function : public reference { +private: + static reference& handler_storage() { + static sol::reference h; + return h; + } + +public: + static const reference& get_default_handler () { + return handler_storage(); + } + + static void set_default_handler( reference& ref ) { + handler_storage() = ref; + } + +private: + struct handler { + const reference& target; + int stackindex; + handler(const reference& target) : target(target), stackindex(0) { + if (target.valid()) { + stackindex = lua_gettop(target.lua_state()) + 1; + target.push(); + } + } + ~handler() { + if (stackindex > 0) { + lua_remove(target.lua_state(), stackindex); + } + } + }; + + int luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, handler& h) const { + return lua_pcallk(lua_state(), static_cast(argcount), static_cast(resultcount), h.stackindex, 0, nullptr); + } + + template + auto invoke(types, std::index_sequence, std::ptrdiff_t n, handler& h) const { + luacall(n, sizeof...(Ret), h); + int stacksize = lua_gettop(lua_state()); + int firstreturn = std::max(0, stacksize - static_cast(sizeof...(Ret)) + 1); + auto r = stack::get>(lua_state(), firstreturn); + lua_pop(lua_state(), static_cast(sizeof...(Ret))); + return r; + } + + template + Ret invoke(types, std::index_sequence, std::ptrdiff_t n, handler& h) const { + luacall(n, 1, h); + return stack::pop(lua_state()); + } + + template + void invoke(types, std::index_sequence, std::ptrdiff_t n, handler& h) const { + luacall(n, 0, h); + } + + protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, handler& h) const { + bool handlerpushed = error_handler.valid(); + int stacksize = lua_gettop(lua_state()); + int firstreturn = std::max(1, stacksize - static_cast(n) - 1); + int returncount = 0; + call_status code = call_status::ok; +#ifndef SOL_NO_EXCEPTIONS + auto onexcept = [&](const char* error) { + h.stackindex = 0; + if (h.target.valid()) { + h.target.push(); + stack::push(lua_state(), error); + lua_call(lua_state(), 1, 1); + } + else { + stack::push(lua_state(), error); + } + }; + try { +#endif // No Exceptions + code = static_cast(luacall(n, LUA_MULTRET, h)); + int poststacksize = lua_gettop(lua_state()); + returncount = poststacksize - firstreturn; +#ifndef SOL_NO_EXCEPTIONS + } + // Handle C++ errors thrown from C++ functions bound inside of lua + catch (const char* error) { + onexcept(error); + firstreturn = lua_gettop(lua_state()); + return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + } + catch (const std::exception& error) { + onexcept(error.what()); + firstreturn = lua_gettop(lua_state()); + return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + } + catch (...) { + throw; + } +#endif // No Exceptions + return protected_function_result(lua_state(), firstreturn + ( handlerpushed ? 0 : 1 ), returncount, returncount, code); + } + +public: + sol::reference error_handler; + + protected_function() = default; + protected_function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) { + type_assert(L, index, type::function); + } + protected_function(const protected_function&) = default; + protected_function& operator=(const protected_function&) = default; + protected_function( protected_function&& ) = default; + protected_function& operator=( protected_function&& ) = default; + + template + protected_function_result operator()(Args&&... args) const { + return call<>(std::forward(args)...); + } + + template + decltype(auto) operator()(types, Args&&... args) const { + return call(std::forward(args)...); + } + + template + decltype(auto) call(Args&&... args) const { + handler h(error_handler); + push(); + int pushcount = stack::push_args(lua_state(), std::forward(args)...); + return invoke(types(), std::index_sequence_for(), pushcount, h); + } +}; +} // sol + +#endif // SOL_FUNCTION_HPP diff --git a/sol/protected_function_result.hpp b/sol/protected_function_result.hpp new file mode 100644 index 00000000..129784cf --- /dev/null +++ b/sol/protected_function_result.hpp @@ -0,0 +1,88 @@ +// The MIT License (MIT) + +// Copyright (c) 2013-2016 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_PROTECTED_FUNCTION_RESULT_HPP +#define SOL_PROTECTED_FUNCTION_RESULT_HPP + +#include "reference.hpp" +#include "tuple.hpp" +#include "stack.hpp" +#include "proxy_base.hpp" + +namespace sol { +struct protected_function_result : public proxy_base { +private: + lua_State* L; + int index; + int returncount; + int popcount; + call_status error; + +public: + protected_function_result() = default; + protected_function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_status error = call_status::ok): L(L), index(index), returncount(returncount), popcount(popcount), error(error) { + + } + protected_function_result(const protected_function_result&) = default; + protected_function_result& operator=(const protected_function_result&) = default; + protected_function_result(protected_function_result&& o) : L(o.L), index(o.index), returncount(o.returncount), popcount(o.popcount), error(o.error) { + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.returncount = 0; + o.popcount = 0; + o.error = call_status::runtime; + } + protected_function_result& operator=(protected_function_result&& o) { + L = o.L; + index = o.index; + returncount = o.returncount; + popcount = o.popcount; + error = o.error; + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.returncount = 0; + o.popcount = 0; + o.error = call_status::runtime; + return *this; + } + + bool valid() const { + return error == call_status::ok; + } + + template + T get() const { + return stack::get(L, index); + } + + ~protected_function_result() { + stack::remove(L, index, popcount); + } +}; +} // sol + +#endif // SOL_FUNCTION_RESULT_HPP diff --git a/sol/proxy.hpp b/sol/proxy.hpp index cb3c0b62..9f55a099 100644 --- a/sol/proxy.hpp +++ b/sol/proxy.hpp @@ -25,6 +25,7 @@ #include "traits.hpp" #include "object.hpp" #include "function.hpp" +#include "protected_function.hpp" #include "proxy_base.hpp" namespace sol {