// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Lua scripting module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include namespace Nz { // Functions args inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, bool* arg, TypeTag) { *arg = instance.CheckBoolean(index); return 1; } inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, bool* arg, bool defValue, TypeTag) { *arg = instance.CheckBoolean(index, defValue); return 1; } inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, std::string* arg, TypeTag) { std::size_t strLength = 0; const char* str = instance.CheckString(index, &strLength); arg->assign(str, strLength); return 1; } inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, String* arg, TypeTag) { std::size_t strLength = 0; const char* str = instance.CheckString(index, &strLength); arg->Set(str, strLength); return 1; } template std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) { using UnderlyingT = std::underlying_type_t; return LuaImplQueryArg(instance, index, reinterpret_cast(arg), TypeTag()); } template std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) { using UnderlyingT = std::underlying_type_t; return LuaImplQueryArg(instance, index, reinterpret_cast(arg), static_cast(defValue), TypeTag()); } template std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) { *arg = static_cast(instance.CheckNumber(index)); return 1; } template std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) { *arg = static_cast(instance.CheckNumber(index, static_cast(defValue))); return 1; } template std::enable_if_t::value && !std::is_unsigned::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) { *arg = static_cast(instance.CheckInteger(index)); return 1; } template std::enable_if_t::value && !std::is_unsigned::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) { *arg = static_cast(instance.CheckInteger(index, defValue)); return 1; } template std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) { using SignedT = std::make_signed_t; return LuaImplQueryArg(instance, index, reinterpret_cast(arg), TypeTag()); } template std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) { using SignedT = std::make_signed_t; return LuaImplQueryArg(instance, index, reinterpret_cast(arg), static_cast(defValue), TypeTag()); } template std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, const T& defValue, TypeTag tag) { if (instance.IsValid(index)) return LuaImplQueryArg(instance, index, arg, tag); else { *arg = defValue; return 1; } } template unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) { return LuaImplQueryArg(instance, index, arg, TypeTag()); } template unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, const T& defValue, TypeTag) { return LuaImplQueryArg(instance, index, arg, defValue, TypeTag()); } // Function returns inline int LuaImplReplyVal(const LuaInstance& instance, bool val, TypeTag) { instance.PushBoolean(val); return 1; } inline int LuaImplReplyVal(const LuaInstance& instance, double val, TypeTag) { instance.PushNumber(val); return 1; } inline int LuaImplReplyVal(const LuaInstance& instance, float val, TypeTag) { instance.PushNumber(val); return 1; } template std::enable_if_t::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) { using EnumT = typename std::underlying_type::type; return LuaImplReplyVal(instance, static_cast(val), TypeTag()); } template std::enable_if_t::value && !std::is_unsigned::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) { instance.PushInteger(val); return 1; } template std::enable_if_t::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) { using SignedT = typename std::make_signed::type; return LuaImplReplyVal(instance, static_cast(val), TypeTag()); } inline int LuaImplReplyVal(const LuaInstance& instance, std::string val, TypeTag) { instance.PushString(val.c_str(), val.size()); return 1; } inline int LuaImplReplyVal(const LuaInstance& instance, String val, TypeTag) { instance.PushString(std::move(val)); return 1; } template int LuaImplReplyVal(const LuaInstance& instance, std::pair val, TypeTag>) { int retVal = 0; retVal += LuaImplReplyVal(instance, std::move(val.first), TypeTag()); retVal += LuaImplReplyVal(instance, std::move(val.second), TypeTag()); return retVal; } template struct LuaImplArgProcesser; template<> struct LuaImplArgProcesser { template static unsigned int Process(const LuaInstance& instance, unsigned int argIndex, ArgContainer& args, DefArgContainer& defArgs) { return LuaImplQueryArg(instance, argIndex, &std::get(args), std::get() - N + FirstDefArg - 1>(defArgs), TypeTag()); } }; template<> struct LuaImplArgProcesser { template static unsigned int Process(const LuaInstance& instance, unsigned int argIndex, ArgContainer& args, DefArgContainer& defArgs) { NazaraUnused(defArgs); return LuaImplQueryArg(instance, argIndex, &std::get(args), TypeTag()); } }; template class LuaImplFunctionProxy { public: template class Impl { static constexpr std::size_t ArgCount = sizeof...(Args); static constexpr std::size_t DefArgCount = sizeof...(DefArgs); static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument"); static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount; public: Impl(DefArgs... defArgs) : m_defaultArgs(std::forward(defArgs)...) { } void ProcessArgs(const LuaInstance& instance) const { m_index = 1; ProcessArgs<0, Args...>(instance); } int Invoke(const LuaInstance& instance, void(*func)(Args...)) const { NazaraUnused(instance); Apply(func, m_args); return 0; } template int Invoke(const LuaInstance& instance, Ret(*func)(Args...)) const { return LuaImplReplyVal(instance, std::move(Apply(func, m_args)), TypeTag()); } private: using ArgContainer = std::tuple>...>; using DefArgContainer = std::tuple>...>; template void ProcessArgs(const LuaInstance& instance) const { NazaraUnused(instance); // No argument to process } template void ProcessArgs(const LuaInstance& instance) const { LuaImplArgProcesser<(N >= FirstDefArg)>::template Process(instance, m_index, m_args, m_defaultArgs); } template void ProcessArgs(const LuaInstance& instance) const { ProcessArgs(instance); ProcessArgs(instance); } mutable ArgContainer m_args; DefArgContainer m_defaultArgs; mutable unsigned int m_index; }; }; template class LuaImplMethodProxy { public: template class Impl { static constexpr std::size_t ArgCount = sizeof...(Args); static constexpr std::size_t DefArgCount = sizeof...(DefArgs); static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument"); static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount; public: Impl(DefArgs... defArgs) : m_defaultArgs(std::forward(defArgs)...) { } void ProcessArgs(const LuaInstance& instance) const { m_index = 1; ProcessArgs<0, Args...>(instance); } template std::enable_if_t::value, int> Invoke(const LuaInstance& instance, T& object, void(P::*func)(Args...)) const { NazaraUnused(instance); Apply(object, func, m_args); return 0; } template std::enable_if_t::value, int> Invoke(const LuaInstance& instance, T& object, Ret(P::*func)(Args...)) const { return LuaImplReplyVal(instance, std::move(Apply(object, func, m_args)), TypeTag()); } template std::enable_if_t::value, int> Invoke(const LuaInstance& instance, const T& object, void(P::*func)(Args...) const) const { NazaraUnused(instance); Apply(object, func, m_args); return 0; } template std::enable_if_t::value, int> Invoke(const LuaInstance& instance, const T& object, Ret(P::*func)(Args...) const) const { return LuaImplReplyVal(instance, std::move(Apply(object, func, m_args)), TypeTag()); } template std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, T& object, void(P::*func)(Args...)) const { NazaraUnused(instance); Apply(*object, func, m_args); return 0; } template std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, T& object, Ret(P::*func)(Args...)) const { return LuaImplReplyVal(instance, std::move(Apply(*object, func, m_args)), TypeTag()); } template std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, const T& object, void(P::*func)(Args...) const) const { NazaraUnused(instance); Apply(*object, func, m_args); return 0; } template std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, const T& object, Ret(P::*func)(Args...) const) const { return LuaImplReplyVal(instance, std::move(Apply(*object, func, m_args)), TypeTag()); } private: using ArgContainer = std::tuple>...>; using DefArgContainer = std::tuple>...>; template void ProcessArgs(const LuaInstance& instance) const { NazaraUnused(instance); // No argument to process } template void ProcessArgs(const LuaInstance& instance) const { m_index += LuaImplArgProcesser<(N >= FirstDefArg)>::template Process(instance, m_index, m_args, m_defaultArgs); } template void ProcessArgs(const LuaInstance& instance) const { ProcessArgs(instance); ProcessArgs(instance); } mutable ArgContainer m_args; DefArgContainer m_defaultArgs; mutable unsigned int m_index; }; }; template T LuaInstance::Check(int* index) const { NazaraAssert(index, "Invalid index pointer"); T object; *index += LuaImplQueryArg(*this, *index, &object, TypeTag()); return object; } template T LuaInstance::Check(int* index, T defValue) const { NazaraAssert(index, "Invalid index pointer"); T object; *index += LuaImplQueryArg(*this, *index, &object, defValue, TypeTag()); return object; } template T LuaInstance::CheckField(const char* fieldName, int tableIndex) const { T object; GetField(fieldName, tableIndex); tableIndex += LuaImplQueryArg(*this, -1, &object, TypeTag()); Pop(); return object; } template T LuaInstance::CheckField(const String& fieldName, int tableIndex) const { return CheckField(fieldName.GetConstBuffer(), tableIndex); } template T LuaInstance::CheckField(const char* fieldName, T defValue, int tableIndex) const { T object; GetField(fieldName, tableIndex); tableIndex += LuaImplQueryArg(*this, -1, &object, defValue, TypeTag()); Pop(); return object; } template T LuaInstance::CheckField(const String& fieldName, T defValue, int tableIndex) const { return CheckField(fieldName.GetConstBuffer(), defValue, tableIndex); } template T LuaInstance::CheckGlobal(const char* fieldName) const { T object; GetGlobal(fieldName); LuaImplQueryArg(*this, -1, &object, TypeTag()); Pop(); return object; } template T LuaInstance::CheckGlobal(const String& fieldName) const { return CheckGlobal(fieldName.GetConstBuffer()); } template T LuaInstance::CheckGlobal(const char* fieldName, T defValue) const { T object; GetGlobal(fieldName); LuaImplQueryArg(*this, -1, &object, defValue, TypeTag()); Pop(); return object; } template T LuaInstance::CheckGlobal(const String& fieldName, T defValue) const { return CheckGlobal(fieldName.GetConstBuffer(), defValue); } template int LuaInstance::Push(T arg) const { return LuaImplReplyVal(*this, std::move(arg), TypeTag()); } template void LuaInstance::PushFunction(R(*func)(Args...), DefArgs&&... defArgs) const { typename LuaImplFunctionProxy::template Impl handler(std::forward(defArgs)...); PushFunction([func, handler] (LuaInstance& lua) -> int { handler.ProcessArgs(lua); return handler.Invoke(lua, func); }); } template void LuaInstance::PushInstance(const char* tname, T* instance) const { T** userdata = static_cast(PushUserdata(sizeof(T*))); *userdata = instance; SetMetatable(tname); } template void LuaInstance::PushInstance(const char* tname, Args&&... args) const { PushInstance(tname, new T(std::forward(args)...)); } template void LuaInstance::SetField(const char* name, T&& arg, int tableIndex) { Push(std::forward(arg)); SetField(name, tableIndex); } template void LuaInstance::SetField(const String& name, T&& arg, int tableIndex) { SetField(name.GetConstBuffer(), std::forward(arg), tableIndex); } template void LuaInstance::SetGlobal(const char* name, T&& arg) { Push(std::forward(arg)); SetGlobal(name); } template void LuaInstance::SetGlobal(const String& name, T&& arg) { SetGlobal(name.GetConstBuffer(), std::forward(arg)); } }