/* * Tencent is pleased to support the open source community by making Puerts available. * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. * Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may * be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE', * which is part of this source code package. */ #pragma once #include #include #include #include "TypeInfo.hpp" #include #if defined(WITH_THROW_IN_CPP) && !defined(THREAD_LOCAL_IMPL_THROW) #include #include #endif namespace PUERTS_NAMESPACE { template struct ArgumentBufferType { using type = typename std::decay::type*; }; template unsigned int Count(Args&&... args) { return sizeof...(Args); } template struct ArgumentBufferType::value && !std::is_const::value>::type> { using type = typename std::decay::type; }; template struct ArgumentBufferType::value && !std::is_const::type>::value && std::is_constructible::type>::value && std::is_copy_constructible::type>::value && std::is_destructible::type>::value>::type> { using type = typename std::decay::type; }; namespace internal { template struct ConverterDecay { using type = typename std::decay::type; }; template struct ConverterDecay::value && !std::is_const::type>::value>::type> { using type = std::reference_wrapper::type>; }; template using Void_t = void; namespace traits { template struct TupleTrait; template struct TupleTrait> { using Head = HeadT; using Tail = std::tuple; static constexpr size_t count = 1 + sizeof...(TailT); template using Arg = typename std::tuple_element>::type; }; template <> struct TupleTrait> { using Tail = std::tuple<>; static constexpr size_t count = 0; }; template struct FunctionTrait; template struct FunctionTrait { using ReturnType = Ret; using Arguments = std::tuple; }; template struct FunctionTrait : FunctionTrait { }; template struct FunctionTrait : FunctionTrait { }; template struct FunctionTrait : FunctionTrait { }; template struct FunctionTrait : FunctionTrait { }; // functor and lambda template struct FunctionTrait> { private: using FunctorTrait = FunctionTrait; public: using ReturnType = typename FunctorTrait::ReturnType; using Arguments = typename TupleTrait::Tail; }; // decay: remove const, reference; function type to function pointer template struct FunctionTrait::type>::value>::type> : FunctionTrait::type> { }; } // namespace traits template struct ArgumentChecker { static bool Check(typename API::CallbackInfoType Info, typename API::ContextType Context) { return true; } }; template struct ArgumentChecker { static constexpr int NextPos = Pos + 1; template using DecayTypeConverter = typename API::template Converter::type>; static bool Check(typename API::CallbackInfoType Info, typename API::ContextType Context) { if (Pos >= StopPos) return true; if (!DecayTypeConverter::accept(Context, API::GetArg(Info, Pos))) { return false; } return ArgumentChecker::Check(Info, Context); } }; template struct ExceptionHandle; template struct ExceptionHandle::value>::type> { #if defined(WITH_THROW_IN_CPP) && defined(THREAD_LOCAL_IMPL_THROW) // TripleOp : 1. init; 2. get state; 3. throw static bool TripleOp(typename API::CallbackInfoType info, const char* error_msg, bool b_get_state) { thread_local typename API::CallbackInfoType s_info; thread_local bool s_throwed; if (b_get_state) { return s_throwed; } if (error_msg) { API::ThrowException(s_info, error_msg); s_throwed = true; return true; } else { s_info = info; s_throwed = false; return false; } } #endif static void Throw(const char* error_msg) { #if defined(WITH_THROW_IN_CPP) && defined(THREAD_LOCAL_IMPL_THROW) // throw TripleOp(nullptr, error_msg, false); #endif } }; #if defined(WITH_THROW_IN_CPP) && !defined(THREAD_LOCAL_IMPL_THROW) struct UserException : std::exception { UserException(const char* msg) { auto len = strlen(msg); Msg = new char[len + 1]; strncpy(Msg, msg, len); Msg[len] = '\0'; } ~UserException() noexcept { delete[] Msg; } const char* what() const noexcept override { return Msg; } char* Msg; }; #endif template struct ExceptionHandle::value>::type> { #if defined(WITH_THROW_IN_CPP) && defined(THREAD_LOCAL_IMPL_THROW) // Triple operate // 1. init: info is not null, error_msg is null, b_get_state is false; // 2. get state: b_get_state is true; // 3. throw: error_msg is not null, b_get_state is false; static bool TripleOp(typename API::CallbackInfoType info, const char* error_msg, bool b_get_state) { thread_local typename std::decay::type* s_info; thread_local bool s_throwed; if (b_get_state) { return s_throwed; } if (error_msg) { API::ThrowException(*s_info, error_msg); s_throwed = true; return true; } else { s_info = (typename std::decay::type*) &info; s_throwed = false; return false; } } #endif static void Throw(const char* error_msg) { #if defined(WITH_THROW_IN_CPP) #if defined(THREAD_LOCAL_IMPL_THROW) typename std::decay::type* pinfo = nullptr; // throw TripleOp(*pinfo, error_msg, false); #else throw UserException(error_msg); #endif #endif } }; template struct FuncCallHelper { }; template struct FuncCallHelper>, CheckArguments, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData> { private: template struct ArgumentsChecker; template using DecayTypeConverter = typename API::template Converter::type>; template struct ArgumentsChecker { static constexpr auto ArgsLength = sizeof...(CArgs); static bool Check(typename API::ContextType context, typename API::CallbackInfoType info) { if (ND == 0 ? API::GetArgsLen(info) != ArgsLength : API::GetArgsLen(info) < (ArgsLength - ND)) return false; if (!ArgumentChecker::Check(info, context)) return false; return true; } }; template struct ArgumentsChecker { static constexpr auto ArgsLength = sizeof...(CArgs); static bool Check(typename API::ContextType context, typename API::CallbackInfoType info) { return true; } }; template struct ArgumentType { using type = typename std::decay::type; }; template struct ArgumentType::type>::value || is_uetype::type>::value) && std::is_lvalue_reference::value>::type> { using type = std::reference_wrapper::type>; }; static constexpr auto ArgsLength = sizeof...(Args); template struct ReturnConverter { static typename API::ValueType Convert(typename API::ContextType context, T ret) { return DecayTypeConverter::type>::toScript(context, std::forward(ret)); } }; template struct ReturnConverter::value && !std::is_const::value)) && (is_objecttype::type>::value || is_uetype::type>::value)>::type> { static typename API::ValueType Convert(typename API::ContextType context, const typename std::decay::type& ret) { return DecayTypeConverter::type*>::toScript( context, &(const_cast::type&>(ret))); } }; template struct ArgumentHolder { typename ArgumentType::type Arg; using ArgumentDecayType = typename std::decay::type; ArgumentHolder(std::tuple info) : Arg(DecayTypeConverter::toCpp(std::get<0>(info), std::get<1>(info))) { } typename ArgumentType::type& GetArgument() { return Arg; } void SetArgument(typename ArgumentType::type InArg) { Arg = InArg; } void SetRef(typename API::ContextType context, typename API::ValueType holder) { } }; template struct ArgumentHolder::type>::value || is_uetype::type>::value) && std::is_lvalue_reference::value && !std::is_const::type>::value && std::is_constructible::type>::value && std::is_copy_constructible::type>::value && std::is_destructible::type>::value>::type> { typename ArgumentType::type Arg; typename ArgumentBufferType::type Buf; ArgumentHolder(std::tuple info) : Arg(*DecayTypeConverter::type>::toCpp(std::get<0>(info), std::get<1>(info))) { if (&(Arg.get()) == nullptr) { Arg = Buf; } } ArgumentHolder(const ArgumentHolder&& other) noexcept : Arg(other.Arg) { if (&(other.Buf) == &(other.Arg.get())) { Arg = Buf; } } typename ArgumentType::type& GetArgument() { return Arg; } void SetArgument(typename ArgumentType::type InArg) { Arg = InArg; } void SetRef(typename API::ContextType context, typename API::ValueType holder) { if (&Buf != &(Arg.get())) { return; } // new object and set API::UpdateRefValue( context, holder, API::template Converter::type>::toScript(context, Arg.get())); } }; template struct ArgumentHolder::type>::value || is_uetype::type>::value) && std::is_lvalue_reference::value && !std::is_const::type>::value && (!std::is_constructible::type>::value || !std::is_copy_constructible::type>::value || !std::is_destructible::type>::value)>::type> { typename ArgumentType::type Arg; // there may be nullptr ref ArgumentHolder(std::tuple info) : Arg(*DecayTypeConverter::type>::toCpp(std::get<0>(info), std::get<1>(info))) { } typename ArgumentType::type& GetArgument() { return Arg; } void SetArgument(typename ArgumentType::type InArg) { Arg = InArg; } void SetRef(typename API::ContextType context, typename API::ValueType holder) { } }; template struct ArgumentHolder::type>::value || is_uetype::type>::value) && std::is_lvalue_reference::value && std::is_const::type>::value>::type> { typename ArgumentType::type Arg; // there may be nullptr ref ArgumentHolder(std::tuple info) : Arg(*DecayTypeConverter::type*>::toCpp(std::get<0>(info), std::get<1>(info))) { } typename ArgumentType::type& GetArgument() { return Arg; } using BuffType = typename std::remove_const::type>::type; BuffType Buf; void SetArgument(BuffType InArg) { Buf = InArg; Arg = Buf; } void SetRef(typename API::ContextType context, typename API::ValueType holder) { } }; template struct ArgumentHolder::type>::value && !is_uetype::type>::value && std::is_lvalue_reference::value && !std::is_const::type>::value>::type> { typename ArgumentType::type Arg; using ArgumentDecayType = typename std::decay::type; ArgumentHolder(std::tuple info) : Arg(DecayTypeConverter>::toCpp(std::get<0>(info), std::get<1>(info))) { } typename ArgumentType::type& GetArgument() { return Arg; } void SetArgument(typename ArgumentType::type InArg) { Arg = InArg; } void SetRef(typename API::ContextType context, typename API::ValueType holder) { API::UpdateRefValue(context, holder, API::template Converter::type>::toScript(context, Arg)); } }; template struct ArgumentHolder::type>::type>::value && !API::template CustomArgumentBufferType::enable && std::is_pointer::value>::type> { T Arg = nullptr; using BuffType = typename std::remove_const::type>::type; BuffType Buf; ArgumentHolder(std::tuple info) : Buf(DecayTypeConverter>::toCpp(std::get<0>(info), std::get<1>(info))) { } T GetArgument() { return Arg ? Arg : &Buf; } void SetArgument(BuffType InArg) { Buf = InArg; } void SetRef(typename API::ContextType context, typename API::ValueType holder) { API::UpdateRefValue(context, holder, API::template Converter::toScript(context, Buf)); } }; template struct ArgumentHolder::type>::type>::value && !API::template CustomArgumentBufferType::enable && std::is_pointer::value>::type> { T Arg = nullptr; ArgumentHolder(std::tuple info) : Arg(DecayTypeConverter::toCpp(std::get<0>(info), std::get<1>(info))) { } T GetArgument() { return Arg; } void SetArgument(T InArg) { Arg = InArg; } void SetRef(typename API::ContextType context, typename API::ValueType holder) { } }; template struct ArgumentHolder::enable>::type> { typename ArgumentType::type Arg; typename API::template CustomArgumentBufferType::type Buf; ArgumentHolder(std::tuple info) : Buf(std::get<0>(info), std::get<1>(info)) { Arg = Buf.Data(); } typename ArgumentType::type GetArgument() { return Arg; } void SetArgument(typename ArgumentType::type InArg) { Arg = InArg; } void SetRef(typename API::ContextType context, typename API::ValueType holder) { } }; using ArgumentsHolder = std::tuple...>; template struct RefValuesSync { static void Sync(typename API::ContextType context, typename API::CallbackInfoType info, ArgumentsHolder& cppArgHolders) { } }; template struct RefValuesSync { static void Sync(typename API::ContextType context, typename API::CallbackInfoType info, ArgumentsHolder& cppArgHolders) { std::get(cppArgHolders).SetRef(context, API::GetArg(info, Pos)); RefValuesSync::Sync(context, info, cppArgHolders); } }; template struct DefaultValueSetter; template struct DefaultValueSetter : DefaultValueSetter { }; template struct DefaultValueSetter<0, Pos, T, FullArgs...> { template static void Set(ArgumentsHolder& cppArgHolders, int argCount, T1 defaultValue, const DefaultArguments&... rest) { if (argCount <= Pos) { std::get(cppArgHolders).SetArgument(defaultValue); } DefaultValueSetter<0, Pos + 1, FullArgs...>::Set(cppArgHolders, argCount, rest...); } }; template struct DefaultValueSetter<0, Pos> { static void Set(ArgumentsHolder& cppArgHolders, int argCount) { } }; template static typename std::enable_if::ReturnType, void>::value, bool>::type call(Func& func, typename API::CallbackInfoType info, std::index_sequence, DefaultArguments&&... defaultValues) { auto context = API::GetContext(info); if (!ArgumentsChecker::Check(context, info)) return false; ArgumentsHolder cppArgHolders( std::tuple{context, API::GetArg(info, index)}...); DefaultValueSetter::type...>::Set( cppArgHolders, API::GetArgsLen(info), std::forward(defaultValues)...); func(std::forward(std::get(cppArgHolders).GetArgument())...); RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders); return true; } template static typename std::enable_if::ReturnType, void>::value, bool>::type call(Func& func, typename API::CallbackInfoType info, std::index_sequence, DefaultArguments&&... defaultValues) { auto context = API::GetContext(info); if (!ArgumentsChecker::Check(context, info)) return false; ArgumentsHolder cppArgHolders( std::tuple{context, API::GetArg(info, index)}...); DefaultValueSetter::type...>::Set( cppArgHolders, API::GetArgsLen(info), std::forward(defaultValues)...); API::SetReturn(info, ReturnConverter::Convert(context, std::forward(func(std::forward(std::get(cppArgHolders).GetArgument())...)))); RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders); return true; } template struct SelfGetter; template struct SelfGetter { static Ins* Get(typename API::ContextType context, typename API::CallbackInfoType info) { return DecayTypeConverter::toCpp(context, API::GetHolder(info)); } }; template struct SelfGetter { static Ins* Get(typename API::ContextType context, typename API::CallbackInfoType info) { return static_cast(API::GetFunctionData(info)); } }; template static typename std::enable_if::ReturnType, void>::value, bool>::type callMethod( Func& func, typename API::CallbackInfoType info, std::index_sequence, DefaultArguments&&... defaultValues) { auto context = API::GetContext(info); auto self = SelfGetter::Get(context, info); if (!self) { API::ThrowException(info, "access a null object"); return true; } if (!ArgumentsChecker::Check(context, info)) return false; ArgumentsHolder cppArgHolders( std::tuple{context, API::GetArg(info, index)}...); DefaultValueSetter::type...>::Set( cppArgHolders, API::GetArgsLen(info), std::forward(defaultValues)...); (self->*func)(std::forward(std::get(cppArgHolders).GetArgument())...); RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders); return true; } template static typename std::enable_if::ReturnType, void>::value, bool>::type callMethod( Func& func, typename API::CallbackInfoType info, std::index_sequence, DefaultArguments&&... defaultValues) { auto context = API::GetContext(info); auto self = SelfGetter::Get(context, info); if (!self) { API::ThrowException(info, "access a null object"); return true; } if (!ArgumentsChecker::Check(context, info)) return false; ArgumentsHolder cppArgHolders( std::tuple{context, API::GetArg(info, index)}...); DefaultValueSetter::type...>::Set( cppArgHolders, API::GetArgsLen(info), std::forward(defaultValues)...); API::SetReturn( info, ReturnConverter::Convert(context, std::forward((self->*func)(std::forward(std::get(cppArgHolders).GetArgument())...)))); RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders); return true; } template static typename std::enable_if::ReturnType, void>::value, bool>::type callExtension( Func& func, typename API::CallbackInfoType info, std::index_sequence, DefaultArguments&&... defaultValues) { auto context = API::GetContext(info); auto self = DecayTypeConverter::toCpp(context, API::GetHolder(info)); if (!self) { API::ThrowException(info, "access a null object"); return true; } if (!ArgumentsChecker::Check(context, info)) return false; ArgumentsHolder cppArgHolders( std::tuple{context, API::GetArg(info, index)}...); DefaultValueSetter::type...>::Set( cppArgHolders, API::GetArgsLen(info), std::forward(defaultValues)...); func(*self, std::forward(std::get(cppArgHolders).GetArgument())...); RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders); return true; } template static typename std::enable_if::ReturnType, void>::value, bool>::type callExtension( Func& func, typename API::CallbackInfoType info, std::index_sequence, DefaultArguments&&... defaultValues) { auto context = API::GetContext(info); auto self = DecayTypeConverter::toCpp(context, API::GetHolder(info)); if (!self) { API::ThrowException(info, "access a null object"); return true; } if (!ArgumentsChecker::Check(context, info)) return false; ArgumentsHolder cppArgHolders( std::tuple{context, API::GetArg(info, index)}...); DefaultValueSetter::type...>::Set( cppArgHolders, API::GetArgsLen(info), std::forward(defaultValues)...); API::SetReturn( info, ReturnConverter::Convert(context, std::forward(func(*self, std::forward(std::get(cppArgHolders).GetArgument())...)))); RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders); return true; } public: template static bool call(Func&& func, typename API::CallbackInfoType info, DefaultArguments&&... defaultValues) { static_assert(sizeof...(Args) >= sizeof...(DefaultArguments), "too many default arguments"); #if defined(WITH_THROW_IN_CPP) #if !defined(THREAD_LOCAL_IMPL_THROW) try { #else // init ExceptionHandle::TripleOp(info, nullptr, false); #endif #endif return call(func, info, std::make_index_sequence(), std::forward(defaultValues)...); #if defined(WITH_THROW_IN_CPP) #if !defined(THREAD_LOCAL_IMPL_THROW) } catch (std::exception& e) { API::ThrowException(info, e.what()); return true; } #endif #endif } template static bool callMethod(Func&& func, typename API::CallbackInfoType info, DefaultArguments&&... defaultValues) { static_assert(sizeof...(Args) >= sizeof...(DefaultArguments), "too many default arguments"); #if defined(WITH_THROW_IN_CPP) #if !defined(THREAD_LOCAL_IMPL_THROW) try { #else // init ExceptionHandle::TripleOp(info, nullptr, false); #endif #endif return callMethod( func, info, std::make_index_sequence(), std::forward(defaultValues)...); #if defined(WITH_THROW_IN_CPP) #if !defined(THREAD_LOCAL_IMPL_THROW) } catch (std::exception& e) { API::ThrowException(info, e.what()); return true; } #endif #endif } template static bool callExtension(Func&& func, typename API::CallbackInfoType info, DefaultArguments&&... defaultValues) { static_assert(sizeof...(Args) >= sizeof...(DefaultArguments), "too many default arguments"); #if defined(WITH_THROW_IN_CPP) #if !defined(THREAD_LOCAL_IMPL_THROW) try { #else // init ExceptionHandle::TripleOp(info, nullptr, false); #endif #endif return callExtension( func, info, std::make_index_sequence(), std::forward(defaultValues)...); #if defined(WITH_THROW_IN_CPP) #if !defined(THREAD_LOCAL_IMPL_THROW) } catch (std::exception& e) { API::ThrowException(info, e.what()); return true; } #endif #endif } }; } // namespace internal template struct FuncCallWrapper; template struct FuncCallWrapper { static void call(typename API::CallbackInfoType info) { using Helper = internal::FuncCallHelper>, false, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; Helper::call(func, info); } static bool overloadCall(typename API::CallbackInfoType info) { using Helper = internal::FuncCallHelper>, true, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; return Helper::call(func, info); } static void checkedCall(typename API::CallbackInfoType info) { using Helper = internal::FuncCallHelper>, true, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; if (!Helper::call(func, info)) { API::ThrowException(info, "invalid parameter!"); } } template static void callWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues) { using Helper = internal::FuncCallHelper>, false, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; Helper::call(func, info, std::forward(defaultValues)...); } template static bool overloadCallWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues) { using Helper = internal::FuncCallHelper>, true, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; return Helper::call(func, info, std::forward(defaultValues)...); } static const CFunctionInfo* info(unsigned int defaultCount = 0) { return CFunctionInfoByPtrImpl::get(defaultCount); } template struct ExtensionCallHelper { template static void call(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues) { using FirstDecayType = typename std::decay::type; using Helper = internal::FuncCallHelper>, false, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; Helper::template callExtension(func, info, std::forward(defaultValues)...); } }; template static void callExtensionWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues) { ExtensionCallHelper::call(info, std::forward(defaultValues)...); } static const CFunctionInfo* extensionInfo(unsigned int defaultCount = 0) { return CFunctionInfoByPtrImpl::get(defaultCount); } }; template struct FuncCallWrapper { static void call(typename API::CallbackInfoType info) { using Helper = internal::FuncCallHelper>, false, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; Helper::template callMethod(func, info); } static bool overloadCall(typename API::CallbackInfoType info) { using Helper = internal::FuncCallHelper>, true, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; return Helper::template callMethod(func, info); } static void checkedCall(typename API::CallbackInfoType info) { using Helper = internal::FuncCallHelper>, true, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; if (!Helper::template callMethod(func, info)) { API::ThrowException(info, "invalid parameter!"); } } template static void callWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues) { using Helper = internal::FuncCallHelper>, false, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; Helper::template callMethod(func, info, std::forward(defaultValues)...); } template static bool overloadCallWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues) { using Helper = internal::FuncCallHelper>, true, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; return Helper::template callMethod(func, info, std::forward(defaultValues)...); } static const CFunctionInfo* info(unsigned int defaultCount = 0) { return CFunctionInfoByPtrImpl::get(defaultCount); } }; // TODO: Similar logic... template struct FuncCallWrapper { static void call(typename API::CallbackInfoType info) { using Helper = internal::FuncCallHelper>, false, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; Helper::template callMethod(func, info); } static bool overloadCall(typename API::CallbackInfoType info) { using Helper = internal::FuncCallHelper>, true, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; return Helper::template callMethod(func, info); } static void checkedCall(typename API::CallbackInfoType info) { using Helper = internal::FuncCallHelper>, true, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; if (!Helper::template callMethod(func, info)) { API::ThrowException(info, "invalid parameter!"); } } template static void callWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues) { using Helper = internal::FuncCallHelper>, false, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; Helper::template callMethod(func, info, std::forward(defaultValues)...); } template static bool overloadCallWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues) { using Helper = internal::FuncCallHelper>, true, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>; return Helper::template callMethod(func, info, std::forward(defaultValues)...); } static const CFunctionInfo* info(unsigned int defaultCount = 0) { return CFunctionInfoByPtrImpl::get(defaultCount); } }; template struct ConstructorWrapper { private: template using DecayTypeConverter = typename API::template Converter::type>; static constexpr auto ArgsLength = sizeof...(Args); template struct Finalize { static void Do(const FT*) { } }; template struct Finalize::value>::type> { static void Do(const FT* Ptr) { delete Ptr; } }; template static void* call(typename API::CallbackInfoType info, std::index_sequence) { auto context = API::GetContext(info); if (API::GetArgsLen(info) != ArgsLength) { return nullptr; } if (!internal::ArgumentChecker::Check(info, context)) { return nullptr; } #if defined(WITH_THROW_IN_CPP) && defined(THREAD_LOCAL_IMPL_THROW) internal::ExceptionHandle::TripleOp(info, nullptr, false); #endif T* obj = new T(DecayTypeConverter::toCpp(context, API::GetArg(info, index))...); #if defined(WITH_THROW_IN_CPP) && defined(THREAD_LOCAL_IMPL_THROW) // get state if (internal::ExceptionHandle::TripleOp(info, nullptr, true)) { Finalize::Do(obj); obj = nullptr; } #endif return obj; } public: static void* call(typename API::CallbackInfoType info) { return call(info, std::make_index_sequence()); } static void* checkedCall(typename API::CallbackInfoType info) { #if defined(WITH_THROW_IN_CPP) && !defined(THREAD_LOCAL_IMPL_THROW) try { #endif auto ret = call(info); if (!ret) { #if defined(WITH_THROW_IN_CPP) && defined(THREAD_LOCAL_IMPL_THROW) // get state, if not exception if (!internal::ExceptionHandle::TripleOp(info, nullptr, true)) #endif API::ThrowException(info, "invalid parameter!"); } return ret; #if defined(WITH_THROW_IN_CPP) && !defined(THREAD_LOCAL_IMPL_THROW) } catch (std::exception& e) { API::ThrowException(info, e.what()); } return nullptr; #endif } static const CFunctionInfo* info(unsigned int defaultCount = 0) { return CFunctionInfoImpl::get(defaultCount); } }; template struct ConstructorsCombiner { template struct ConstructorRecursion { static void* _call(typename API::CallbackInfoType info) { auto Ret = Func(info); if (Ret) return Ret; #if defined(WITH_THROW_IN_CPP) && defined(THREAD_LOCAL_IMPL_THROW) // get state, if not exception if (internal::ExceptionHandle::TripleOp(info, nullptr, true)) { return Ret; } #endif // try next overload return ConstructorRecursion::_call(info); } static void* call(typename API::CallbackInfoType info) { #if defined(WITH_THROW_IN_CPP) && !defined(THREAD_LOCAL_IMPL_THROW) try { #endif auto Ret = _call(info); if (!Ret) { #if defined(WITH_THROW_IN_CPP) && defined(THREAD_LOCAL_IMPL_THROW) // get state, if not exception if (!internal::ExceptionHandle::TripleOp(info, nullptr, true)) #endif API::ThrowException(info, "invalid parameter!"); } return Ret; #if defined(WITH_THROW_IN_CPP) && !defined(THREAD_LOCAL_IMPL_THROW) } catch (std::exception& e) { API::ThrowException(info, e.what()); } return nullptr; #endif } }; template struct ConstructorRecursion { static void* _call(typename API::CallbackInfoType info) { return Func(info); } }; static void* call(typename API::CallbackInfoType info) { return ConstructorRecursion<(&OverloadWraps::call)...>::call(info); } static constexpr int length = sizeof...(OverloadWraps); static const CFunctionInfo** infos() { static const CFunctionInfo* _infos[sizeof...(OverloadWraps)] = {OverloadWraps::info()...}; return _infos; } }; template struct OverloadsCombiner { typedef bool (*V8FunctionCallbackWithBoolRet)(typename API::CallbackInfoType info); template struct OverloadsRecursion { static bool _call(typename API::CallbackInfoType info) { if (Func(info)) return true; else return OverloadsRecursion::_call(info); } static void call(typename API::CallbackInfoType info) { if (!_call(info)) { API::ThrowException(info, "invalid parameter!"); } } }; template struct OverloadsRecursion { static bool _call(typename API::CallbackInfoType info) { return Func(info); } }; static void call(typename API::CallbackInfoType info) { OverloadsRecursion<(&OverloadWraps::overloadCall)...>::call(info); } static constexpr int length = sizeof...(OverloadWraps); static const CFunctionInfo** infos() { static const CFunctionInfo* _infos[sizeof...(OverloadWraps)] = {OverloadWraps::info()...}; return _infos; } }; template struct IsBoundedArray : std::false_type { }; template struct IsBoundedArray : std::true_type { }; template struct PropertyWrapper; template struct PropertyWrapper::value && !is_uetype::value && !IsBoundedArray::value>::type> { template using DecayTypeConverter = typename API::template Converter::type>; using SelfType = typename std::conditional::value, Ins, IncPass>::type; static void getter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); auto self = DecayTypeConverter::toCpp(context, API::GetThis(info)); if (!self) { API::ThrowException(info, "access a null object"); return; } API::SetReturn(info, DecayTypeConverter::toScript(context, self->*member)); } static void setter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); auto self = DecayTypeConverter::toCpp(context, API::GetThis(info)); if (!self) { API::ThrowException(info, "access a null object"); return; } self->*member = DecayTypeConverter::toCpp(context, API::GetArg(info, 0)); } static const CTypeInfo* info() { return CTypeInfoImpl::get(); } }; template struct PropertyWrapper::value && !is_uetype::value && IsBoundedArray::value>::type> { template using DecayTypeConverter = typename API::template Converter::type>; using SelfType = typename std::conditional::value, Ins, IncPass>::type; static void getter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); auto self = DecayTypeConverter::toCpp(context, API::GetThis(info)); if (!self) { API::ThrowException(info, "access a null object"); return; } API::SetReturn(info, API::template Converter::toScript(context, self->*member)); } static void setter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); auto self = DecayTypeConverter::toCpp(context, API::GetThis(info)); if (!self) { API::ThrowException(info, "access a null object"); return; } if (!API::template Converter::accept(context, API::GetArg(info, 0))) { API::ThrowException(info, "invalid value for property"); return; } auto Src = DecayTypeConverter::toCpp(context, API::GetArg(info, 0)); if (self->*member == Src) { return; } memcpy(self->*member, Src, sizeof(Ret)); } static const CTypeInfo* info() { return CTypeInfoImpl::get(); } }; template struct PropertyWrapper::value || is_uetype::value>::type> { template using DecayTypeConverter = typename API::template Converter::type>; using SelfType = typename std::conditional::value, Ins, IncPass>::type; static void getter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); auto self = DecayTypeConverter::toCpp(context, API::GetThis(info)); if (!self) { API::ThrowException(info, "access a null object"); return; } auto ret = DecayTypeConverter::toScript(context, &(self->*member)); API::template LinkOuter(context, API::GetThis(info), ret); API::SetReturn(info, ret); } static void setter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); auto self = DecayTypeConverter::toCpp(context, API::GetThis(info)); if (!self) { API::ThrowException(info, "access a null object"); return; } self->*member = DecayTypeConverter::toCpp(context, API::GetArg(info, 0)); } static const CTypeInfo* info() { return CTypeInfoImpl::get(); } }; template struct PropertyWrapper { template using DecayTypeConverter = typename API::template Converter::type>; static void getter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); API::SetReturn(info, DecayTypeConverter::toScript(context, *Variable)); } static void setter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); *Variable = DecayTypeConverter::toCpp(context, API::GetArg(info, 0)); } static const CTypeInfo* info() { return CTypeInfoImpl::get(); } }; template struct PropertyGetterWrapper; template struct PropertyGetterWrapper { template using DecayTypeConverter = typename API::template Converter::type>; static void getter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); API::SetReturn(info, DecayTypeConverter::toScript(context, fgetter())); } }; template struct PropertyGetterWrapper { template using DecayTypeConverter = typename API::template Converter::type>; static void getter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); auto self = DecayTypeConverter::toCpp(context, API::GetThis(info)); if (!self) { API::ThrowException(info, "access a null object"); return; } API::SetReturn(info, API::template Converter::toScript(context, (self->*func)())); } }; template struct PropertyGetterWrapper { template using DecayTypeConverter = typename API::template Converter::type>; static void getter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); auto self = DecayTypeConverter::toCpp(context, API::GetThis(info)); if (!self) { API::ThrowException(info, "access a null object"); return; } API::SetReturn(info, API::template Converter::toScript(context, (self->*func)())); } }; template struct PropertyGetterWrapper { static void getter(typename API::CallbackInfoType info) { API::ThrowException(info, "not getter for this property!"); } }; template struct PropertySetterWrapper; template struct PropertySetterWrapper { template using DecayTypeConverter = typename API::template Converter::type>; static void setter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); fsetter(DecayTypeConverter::toCpp(context, API::GetArg(info, 0))); } }; template struct PropertySetterWrapper { template using DecayTypeConverter = typename API::template Converter::type>; static void setter(typename API::CallbackInfoType info) { auto context = API::GetContext(info); auto self = DecayTypeConverter::toCpp(context, API::GetThis(info)); if (!self) { API::ThrowException(info, "access a null object"); return; } (self->*func)(DecayTypeConverter::toCpp(context, API::GetArg(info, 0))); } }; template struct PropertySetterWrapper { static void setter(typename API::CallbackInfoType info) { API::ThrowException(info, "not setter for this property!"); } }; template struct PropertyGetterSetterInfo; template struct PropertyGetterSetterInfo { static const CTypeInfo* info() { return CTypeInfoImpl::get(); } }; template struct PropertyGetterSetterInfo { static const CTypeInfo* info() { return CTypeInfoImpl::get(); } }; template struct PropertyGetterSetterInfo { static const CTypeInfo* info() { return CTypeInfoImpl::get(); } }; template struct PropertyGetterSetterInfo { static const CTypeInfo* info() { return CTypeInfoImpl::get(); } }; template struct PropertyGetterSetterInfo { static const CTypeInfo* info() { return CTypeInfoImpl::get(); } }; template class ClassDefineBuilder { template using sfina = ClassDefineBuilder&; public: const char* className_ = nullptr; const void* superTypeId_ = nullptr; std::vector functions_{}; std::vector methods_{}; std::vector properties_{}; std::vector variables_{}; typename API::InitializeFuncType constructor_{}; std::vector constructorInfos_{}; std::vector methodInfos_{}; std::vector functionInfos_{}; std::vector propertyInfos_{}; std::vector variableInfos_{}; explicit ClassDefineBuilder(const char* className) : className_(className) { } template ClassDefineBuilder& Extends() { superTypeId_ = StaticTypeId::get(); return *this; } template ClassDefineBuilder& Constructor() { typename API::InitializeFuncType constructor = ConstructorWrapper::checkedCall; constructor_ = constructor; constructorInfos_.push_back( typename API::GeneralFunctionReflectionInfo{"constructor", ConstructorWrapper::info()}); return *this; } ClassDefineBuilder& Constructor( typename API::InitializeFuncType constructor, int length, const CFunctionInfo** infos) { for (int i = 0; i < length; i++) { constructorInfos_.push_back(typename API::GeneralFunctionReflectionInfo{"constructor", infos[i]}); } constructor_ = constructor; return *this; } ClassDefineBuilder& Function( const char* name, typename API::FunctionCallbackType func, const CFunctionInfo* info) { if (info) { functionInfos_.push_back(typename API::GeneralFunctionReflectionInfo{name, info}); } functions_.push_back(typename API::GeneralFunctionInfo(name, func, nullptr, info)); return *this; } ClassDefineBuilder& Function( const char* name, typename API::FunctionCallbackType func, int length, const CFunctionInfo** infos) { for (int i = 0; i < length; i++) { functionInfos_.push_back(typename API::GeneralFunctionReflectionInfo{name, infos[i]}); } functions_.push_back(typename API::GeneralFunctionInfo(name, func, nullptr, nullptr)); return *this; } ClassDefineBuilder& Method( const char* name, typename API::FunctionCallbackType func, const CFunctionInfo* info) { if (info) { methodInfos_.push_back(typename API::GeneralFunctionReflectionInfo{name, info}); } methods_.push_back(typename API::GeneralFunctionInfo(name, func, nullptr, info)); return *this; } ClassDefineBuilder& Method( const char* name, typename API::FunctionCallbackType func, int length, const CFunctionInfo** infos) { for (int i = 0; i < length; i++) { methodInfos_.push_back(typename API::GeneralFunctionReflectionInfo{name, infos[i]}); } methods_.push_back(typename API::GeneralFunctionInfo(name, func, nullptr, nullptr)); return *this; } template ClassDefineBuilder& MethodProxy(const char* name) { typename API::FunctionCallbackType proxyed = [](typename API::CallbackInfoType info) -> void { using Helper = internal::FuncCallHelper::ReturnType, typename internal::traits::FunctionTrait::Arguments>, false, false, true, false>; Helper::template callMethod(func, info); }; methods_.push_back(typename API::GeneralFunctionInfo(name, proxyed, nullptr, nullptr)); return *this; } ClassDefineBuilder& Property(const char* name, typename API::FunctionCallbackType getter, typename API::FunctionCallbackType setter = nullptr, const CTypeInfo* type = nullptr) { if (type) { propertyInfos_.push_back(typename API::GeneralPropertyReflectionInfo{name, type}); } properties_.push_back(typename API::GeneralPropertyInfo(name, getter, setter, nullptr, nullptr)); return *this; } template ClassDefineBuilder& PropertyProxy(const char* name) { properties_.push_back(typename API::GeneralPropertyInfo( name, &PropertyWrapper::getter, &PropertyWrapper::setter, nullptr, nullptr)); return *this; } ClassDefineBuilder& Variable(const char* name, typename API::FunctionCallbackType getter, typename API::FunctionCallbackType setter = nullptr, const CTypeInfo* type = nullptr) { if (type) { variableInfos_.push_back(typename API::GeneralPropertyReflectionInfo{name, type}); } variables_.push_back(typename API::GeneralPropertyInfo(name, getter, setter, nullptr, nullptr)); return *this; } typedef void (*FinalizeFuncType)(void* Ptr, void* ClassData, void* EnvData); template struct FinalizeBuilder { static FinalizeFuncType Build() { return FinalizeFuncType{}; } }; template struct FinalizeBuilder::value>::type> { static FinalizeFuncType Build() { return [](void* Ptr, void* ClassData, void* EnvData) { delete static_cast(Ptr); }; } }; void Register() { Register(FinalizeBuilder::Build()); } void Register(FinalizeFuncType Finalize) { RegisterAPI::template Register(Finalize, *this); } }; } // namespace PUERTS_NAMESPACE