// https://github.com/vinniefalco/LuaBridge
// Copyright 2020, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/Config.h>
#include <LuaBridge/detail/TypeList.h>
#include <functional>
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<class ReturnType, size_t NUM_PARAMS>
struct Caller;
template<class ReturnType>
struct Caller<ReturnType, 0>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>&)
{
return fn();
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>&)
{
return (obj->*fn)();
}
};
template<class ReturnType>
struct Caller<ReturnType, 1>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 2>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd, tvl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 3>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 4>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return (obj->*fn)(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd);
}
};
template<class ReturnType>
struct Caller<ReturnType, 5>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& tvl)
{
return fn(tvl.hd, tvl.tl.hd, tvl.tl.tl.hd, tvl.tl.tl.tl.hd, tvl.tl.tl.tl.tl.hd);
}
template<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& 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<class ReturnType>
struct Caller<ReturnType, 6>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& 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<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& 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<class ReturnType>
struct Caller<ReturnType, 7>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& 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<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& 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<class ReturnType>
struct Caller<ReturnType, 8>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& 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<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& 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<class ReturnType>
struct Caller<ReturnType, 9>
{
template<class Fn, class Params>
static ReturnType f(Fn& fn, TypeListValues<Params>& 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<class T, class MemFn, class Params>
static ReturnType f(T* obj, MemFn& fn, TypeListValues<Params>& 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<class ReturnType, class Fn, class Params>
ReturnType doCall(Fn& fn, TypeListValues<Params>& tvl)
{
return Caller<ReturnType, TypeListSize<Params>::value>::f(fn, tvl);
}
template<class ReturnType, class T, class MemFn, class Params>
ReturnType doCall(T* obj, MemFn& fn, TypeListValues<Params>& tvl)
{
return Caller<ReturnType, TypeListSize<Params>::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<class MemFn, class D = MemFn>
struct FuncTraits
{
};
/* Ordinary function pointers. */
template<class R, class... ParamList>
struct FuncTraits<R (*)(ParamList...)>
{
static bool const isMemberFunction = false;
using DeclType = R (*)(ParamList...);
using ReturnType = R;
using Params = typename MakeTypeList<ParamList...>::Result;
static R call(const DeclType& fp, TypeListValues<Params>& tvl) { return doCall<R>(fp, tvl); }
};
/* Windows: WINAPI (a.k.a. __stdcall) function pointers. */
#ifdef _M_IX86 // Windows 32bit only
template<class R, class... ParamList>
struct FuncTraits<R(__stdcall*)(ParamList...)>
{
static bool const isMemberFunction = false;
using DeclType = R(__stdcall*)(ParamList...);
using ReturnType = R;
using Params = typename MakeTypeList<ParamList...>::Result;
static R call(const DeclType& fp, TypeListValues<Params>& tvl) { return doCall<R>(fp, tvl); }
};
#endif // _M_IX86
/* Non-const member function pointers. */
template<class T, class R, class... ParamList>
struct FuncTraits<R (T::*)(ParamList...)>
{
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<ParamList...>::Result;
static R call(ClassType* obj, const DeclType& fp, TypeListValues<Params>& tvl)
{
return doCall<R>(obj, fp, tvl);
}
};
/* Const member function pointers. */
template<class T, class R, class... ParamList>
struct FuncTraits<R (T::*)(ParamList...) const>
{
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<ParamList...>::Result;
static R call(const ClassType* obj, const DeclType& fp, TypeListValues<Params>& tvl)
{
return doCall<R>(obj, fp, tvl);
}
};
/* std::function */
template<class R, class... ParamList>
struct FuncTraits<std::function<R(ParamList...)>>
{
static bool const isMemberFunction = false;
static bool const isConstMemberFunction = false;
using DeclType = std::function<R(ParamList...)>;
using ReturnType = R;
using Params = typename MakeTypeList<ParamList...>::Result;
static ReturnType call(DeclType& fn, TypeListValues<Params>& tvl)
{
return doCall<ReturnType>(fn, tvl);
}
};
template<class ReturnType, class Params, int startParam>
struct Invoke
{
template<class Fn>
static int run(lua_State* L, Fn& fn)
{
try
{
ArgList<Params, startParam> args(L);
Stack<ReturnType>::push(L, FuncTraits<Fn>::call(fn, args));
return 1;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
template<class T, class MemFn>
static int run(lua_State* L, T* object, const MemFn& fn)
{
try
{
ArgList<Params, startParam> args(L);
Stack<ReturnType>::push(L, FuncTraits<MemFn>::call(object, fn, args));
return 1;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
};
template<class Params, int startParam>
struct Invoke<void, Params, startParam>
{
template<class Fn>
static int run(lua_State* L, Fn& fn)
{
try
{
ArgList<Params, startParam> args(L);
FuncTraits<Fn>::call(fn, args);
return 0;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
template<class T, class MemFn>
static int run(lua_State* L, T* object, const MemFn& fn)
{
try
{
ArgList<Params, startParam> args(L);
FuncTraits<MemFn>::call(object, fn, args);
return 0;
}
catch (const std::exception& e)
{
return luaL_error(L, e.what());
}
}
};
} // namespace detail
} // namespace luabridge