// 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 bool LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag) { return instance.CheckBoolean(index); } inline bool LuaImplQueryArg(LuaInstance& instance, unsigned int index, bool defValue, TypeTag) { return instance.CheckBoolean(index, defValue); } inline double LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag) { return instance.CheckNumber(index); } inline double LuaImplQueryArg(LuaInstance& instance, unsigned int index, double defValue, TypeTag) { return instance.CheckNumber(index, defValue); } inline float LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag) { return static_cast(instance.CheckNumber(index)); } inline float LuaImplQueryArg(LuaInstance& instance, unsigned int index, float defValue, TypeTag) { return static_cast(instance.CheckNumber(index, defValue)); } template std::enable_if_t::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag) { return static_cast(LuaImplQueryArg(instance, index, TypeTag::type>())); } template std::enable_if_t::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, T defValue, TypeTag) { using UnderlyingT = std::underlying_type_t; return static_cast(LuaImplQueryArg(instance, index, static_cast(defValue), TypeTag())); } template std::enable_if_t::value && !std::is_unsigned::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag) { return static_cast(instance.CheckInteger(index)); } template std::enable_if_t::value && !std::is_unsigned::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, T defValue, TypeTag) { return static_cast(instance.CheckInteger(index, defValue)); } template std::enable_if_t::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag) { using SignedT = std::make_signed_t; return static_cast(LuaImplQueryArg(instance, index, TypeTag())); } template std::enable_if_t::value, T> LuaImplQueryArg(LuaInstance& instance, unsigned int index, T defValue, TypeTag) { using SignedT = std::make_signed_t; return static_cast(LuaImplQueryArg(instance, index, static_cast(defValue), TypeTag())); } inline std::string LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag) { std::size_t strLength = 0; const char* str = instance.CheckString(index, &strLength); return std::string(str, strLength); } inline std::string LuaImplQueryArg(LuaInstance& instance, unsigned int index, const std::string& defValue, TypeTag) { std::size_t strLength = 0; const char* str = instance.CheckString(index, defValue.c_str(), &strLength); return std::string(str, strLength); } inline String LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag) { std::size_t strLength = 0; const char* str = instance.CheckString(index, &strLength); return String(str, strLength); } inline String LuaImplQueryArg(LuaInstance& instance, unsigned int index, const String& defValue, TypeTag) { std::size_t strLength = 0; const char* str = instance.CheckString(index, defValue.GetConstBuffer(), &strLength); return String(str, strLength); } template T LuaImplQueryArg(LuaInstance& instance, unsigned int index, TypeTag) { return LuaImplQueryArg(instance, index, TypeTag()); } template T LuaImplQueryArg(LuaInstance& instance, unsigned int index, const T& defValue, TypeTag tag) { if (instance.IsValid(index)) return LuaImplQueryArg(instance, index, tag); else return defValue; } template T LuaImplQueryArg(LuaInstance& instance, unsigned int index, const T& defValue, TypeTag) { return LuaImplQueryArg(instance, index, defValue, TypeTag()); } // Function returns inline int LuaImplReplyVal(LuaInstance& instance, bool val, TypeTag) { instance.PushBoolean(val); return 1; } inline int LuaImplReplyVal(LuaInstance& instance, double val, TypeTag) { instance.PushNumber(val); return 1; } inline int LuaImplReplyVal(LuaInstance& instance, float val, TypeTag) { instance.PushNumber(val); return 1; } template std::enable_if_t::value, int> LuaImplReplyVal(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(LuaInstance& instance, T val, TypeTag) { instance.PushInteger(val); return 1; } template std::enable_if_t::value, int> LuaImplReplyVal(LuaInstance& instance, T val, TypeTag) { using SignedT = typename std::make_signed::type; return LuaImplReplyVal(instance, static_cast(val), TypeTag()); } inline int LuaImplReplyVal(LuaInstance& instance, std::string val, TypeTag) { instance.PushString(val.c_str(), val.size()); return 1; } inline int LuaImplReplyVal(LuaInstance& instance, String val, TypeTag) { instance.PushString(std::move(val)); return 1; } template int LuaImplReplyVal(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 void Process(LuaInstance& instance, ArgContainer& args, DefArgContainer& defArgs) { std::get(args) = std::move(LuaImplQueryArg(instance, N + 1, std::get(defArgs), TypeTag())); } }; template<> struct LuaImplArgProcesser { template static void Process(LuaInstance& instance, ArgContainer& args, DefArgContainer& defArgs) { NazaraUnused(defArgs); std::get(args) = std::move(LuaImplQueryArg(instance, N + 1, 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(LuaInstance& instance, DefArgs... defArgs) : m_defaultArgs(std::forward(defArgs)...), m_instance(instance), { } void ProcessArgs() { ProcessArgs<0, Args...>(); } int Invoke(void (*func)(Args...)) { Apply(func, m_args); return 0; } template int Invoke(Ret (*func)(Args...)) { return LuaImplReplyVal(m_instance, std::move(Apply(func, m_args)), TypeTag()); } private: using ArgContainer = std::tuple>...>; using DefArgContainer = std::tuple>...>; template void ProcessArgs() { // No argument to process } template void ProcessArgs() { using CheckDefValue = typename std::integral_constant= FirstDefArg>; LuaImplArgProcesser::Process(m_instance, m_args, m_defaultArgs); } template void ProcessArgs() { ProcessArgs(); ProcessArgs(); } ArgContainer m_args; DefArgContainer m_defaultArgs; LuaInstance& m_instance; }; }; 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(LuaInstance& instance, T& object, DefArgs... defArgs) : m_defaultArgs(std::forward(defArgs)...), m_instance(instance), m_object(object) { } void ProcessArgs() { ProcessArgs<0, Args...>(); } template std::enable_if_t::value, int> Invoke(void(P::*func)(Args...)) { Apply(m_object, func, m_args); return 0; } template std::enable_if_t::value, int> Invoke(Ret(P::*func)(Args...)) { return LuaImplReplyVal(m_instance, std::move(Apply(m_object, func, m_args)), TypeTag()); } template std::enable_if_t::value, int> Invoke(void(P::*func)(Args...) const) { Apply(m_object, func, m_args); return 0; } template std::enable_if_t::value, int> Invoke(Ret(P::*func)(Args...) const) { return LuaImplReplyVal(m_instance, std::move(Apply(m_object, func, m_args)), TypeTag()); } private: using ArgContainer = std::tuple>...>; using DefArgContainer = std::tuple>...>; template void ProcessArgs() { // No argument to process } template void ProcessArgs() { using CheckDefValue = typename std::integral_constant= FirstDefArg>; LuaImplArgProcesser::Process(m_instance, m_args, m_defaultArgs); } template void ProcessArgs() { ProcessArgs(); ProcessArgs(); } ArgContainer m_args; DefArgContainer m_defaultArgs; LuaInstance& m_instance; T& m_object; }; }; template T LuaInstance::Check(int index) { return LuaImplQueryArg(*this, index, TypeTag()); } template T LuaInstance::Check(int index, T defValue) { return LuaImplQueryArg(*this, index, defValue, TypeTag()); } template int LuaInstance::Push(T arg) { return LuaImplReplyVal(*this, std::move(arg), TypeTag()); } template void LuaInstance::PushFunction(R (*func)(Args...), DefArgs... defArgs) { PushFunction([func, defArgs...](LuaInstance& instance) -> int { LuaImplFunctionProxy::Impl handler(instance); handler.ProcessArgs(); return handler.Invoke(func); }); } }