// https://github.com/vinniefalco/LuaBridge // Copyright 2020, Dmitry Tarakanov // Copyright 2012, Vinnie Falco // SPDX-License-Identifier: MIT #pragma once #include #include #include namespace luabridge { namespace detail { /** Since the throw specification is part of a function signature, the FuncTraits family of templates needs to be specialized for both types. The LUABRIDGE_THROWSPEC macro controls whether we use the 'throw ()' form, or 'noexcept' (if C++11 is available) to distinguish the functions. */ #if defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__clang__) || defined(__GNUC__) || \ (defined(_MSC_VER) && (_MSC_VER >= 1700)) // Do not define LUABRIDGE_THROWSPEC since the Xcode and gcc compilers do not // distinguish the throw specification in the function signature. #define LUABRIDGE_THROWSPEC #else // Visual Studio 10 and earlier pay too much mind to useless throw () spec. // #define LUABRIDGE_THROWSPEC throw() #endif //============================================================================== /** * Traits class for unrolling the type list values into function arguments. */ template struct Caller; template struct Caller { template static ReturnType f(Fn& fn, TypeListValues&) { return fn(); } template static ReturnType f(T* obj, MemFn& fn, TypeListValues&) { return (obj->*fn)(); } }; template struct Caller { template static ReturnType f(Fn& fn, TypeListValues& tvl) { return fn(tvl.hd); } template static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) { return (obj->*fn)(tvl.hd); } }; template struct Caller { template static ReturnType f(Fn& fn, TypeListValues& tvl) { return fn(tvl.hd, tvl.tl.hd); } template static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) { return (obj->*fn)(tvl.hd, tvl.tl.hd); } }; template struct Caller { template static ReturnType f(Fn& fn, TypeListValues& tvl) { return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); } template static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) { return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd); } }; template struct Caller { template static ReturnType f(Fn& fn, TypeListValues& tvl) { return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); } template static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) { return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd); } }; template struct Caller { template static ReturnType f(Fn& fn, TypeListValues& tvl) { return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd); } template static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) { return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd); } }; template struct Caller { template static ReturnType f(Fn& fn, TypeListValues& tvl) { return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd); } template static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) { return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd); } }; template struct Caller { template static ReturnType f(Fn& fn, TypeListValues& tvl) { return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd); } template static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) { return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd); } }; template struct Caller { template static ReturnType f(Fn& fn, TypeListValues& tvl) { return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.hd); } template static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) { return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.hd); } }; template struct Caller { template static ReturnType f(Fn& fn, TypeListValues& tvl) { return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.tl.hd); } template static ReturnType f(T* obj, MemFn& fn, TypeListValues& tvl) { return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.tl.tl.tl.tl.hd); } }; template ReturnType doCall(Fn& fn, TypeListValues& tvl) { return Caller::value>::f(fn, tvl); } template ReturnType doCall(T* obj, MemFn& fn, TypeListValues& tvl) { return Caller::value>::f(obj, fn, tvl); } //============================================================================== /** Traits for function pointers. There are three types of functions: global, non-const member, and const member. These templates determine the type of function, which class type it belongs to if it is a class member, the const-ness if it is a member function, and the type information for the return value and argument list. Expansions are provided for functions with up to 8 parameters. This can be manually extended, or expanded to an arbitrary amount using C++11 features. */ template struct FuncTraits { }; /* Ordinary function pointers. */ template struct FuncTraits { static bool const isMemberFunction = false; using DeclType = R (*)(ParamList...); using ReturnType = R; using Params = typename MakeTypeList::Result; static R call(const DeclType& fp, TypeListValues& tvl) { return doCall(fp, tvl); } }; /* Windows: WINAPI (a.k.a. __stdcall) function pointers. */ #ifdef _M_IX86 // Windows 32bit only template struct FuncTraits { static bool const isMemberFunction = false; using DeclType = R(__stdcall*)(ParamList...); using ReturnType = R; using Params = typename MakeTypeList::Result; static R call(const DeclType& fp, TypeListValues& tvl) { return doCall(fp, tvl); } }; #endif // _M_IX86 /* Non-const member function pointers. */ template struct FuncTraits { static bool const isMemberFunction = true; static bool const isConstMemberFunction = false; using DeclType = R (T::*)(ParamList...); using ClassType = T; using ReturnType = R; using Params = typename MakeTypeList::Result; static R call(ClassType* obj, const DeclType& fp, TypeListValues& tvl) { return doCall(obj, fp, tvl); } }; /* Const member function pointers. */ template struct FuncTraits { static bool const isMemberFunction = true; static bool const isConstMemberFunction = true; using DeclType = R (T::*)(ParamList...) const; using ClassType = T; using ReturnType = R; using Params = typename MakeTypeList::Result; static R call(const ClassType* obj, const DeclType& fp, TypeListValues& tvl) { return doCall(obj, fp, tvl); } }; /* std::function */ template struct FuncTraits> { static bool const isMemberFunction = false; static bool const isConstMemberFunction = false; using DeclType = std::function; using ReturnType = R; using Params = typename MakeTypeList::Result; static ReturnType call(DeclType& fn, TypeListValues& tvl) { return doCall(fn, tvl); } }; template struct Invoke { template static int run(lua_State* L, Fn& fn) { try { ArgList args(L); Stack::push(L, FuncTraits::call(fn, args)); return 1; } catch (const std::exception& e) { return luaL_error(L, e.what()); } } template static int run(lua_State* L, T* object, const MemFn& fn) { try { ArgList args(L); Stack::push(L, FuncTraits::call(object, fn, args)); return 1; } catch (const std::exception& e) { return luaL_error(L, e.what()); } } }; template struct Invoke { template static int run(lua_State* L, Fn& fn) { try { ArgList args(L); FuncTraits::call(fn, args); return 0; } catch (const std::exception& e) { return luaL_error(L, e.what()); } } template static int run(lua_State* L, T* object, const MemFn& fn) { try { ArgList args(L); FuncTraits::call(object, fn, args); return 0; } catch (const std::exception& e) { return luaL_error(L, e.what()); } } }; } // namespace detail } // namespace luabridge