Files
MingSimulator/Plugins/Puerts/Source/JsEnv/Public/StaticCall.hpp
T
starmen1265 ed21658256 从master分支拉取puerts,并拉取v8制品,修改puerts插件部分UE5_5以下兼容的宏代码。保证puerts编译通过。包括
CSharpParamDefaultValueMetas.cs和ubtplugin.csproj和declarationGenerator.cpp和PropertyTranslator.cpp对UserDefinedStruct.h的引用
2024-12-02 01:03:52 +08:00

1843 lines
62 KiB
C++

/*
* 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 <tuple>
#include <type_traits>
#include <vector>
#include "TypeInfo.hpp"
#include <type_traits>
#if defined(WITH_THROW_IN_CPP) && !defined(THREAD_LOCAL_IMPL_THROW)
#include <exception>
#include <cstring>
#endif
namespace PUERTS_NAMESPACE
{
template <typename T, typename = void>
struct ArgumentBufferType
{
using type = typename std::decay<T>::type*;
};
template <class... Args>
unsigned int Count(Args&&... args)
{
return sizeof...(Args);
}
template <typename T>
struct ArgumentBufferType<T*, typename std::enable_if<is_script_type<T>::value && !std::is_const<T>::value>::type>
{
using type = typename std::decay<T>::type;
};
template <typename T>
struct ArgumentBufferType<T,
typename std::enable_if<std::is_lvalue_reference<T>::value && !std::is_const<typename std::remove_reference<T>::type>::value &&
std::is_constructible<typename std::decay<T>::type>::value &&
std::is_copy_constructible<typename std::decay<T>::type>::value &&
std::is_destructible<typename std::decay<T>::type>::value>::type>
{
using type = typename std::decay<T>::type;
};
namespace internal
{
template <typename T, typename = void>
struct ConverterDecay
{
using type = typename std::decay<T>::type;
};
template <typename T>
struct ConverterDecay<T, typename std::enable_if<std::is_lvalue_reference<T>::value &&
!std::is_const<typename std::remove_reference<T>::type>::value>::type>
{
using type = std::reference_wrapper<typename std::decay<T>::type>;
};
template <class...>
using Void_t = void;
namespace traits
{
template <typename Args>
struct TupleTrait;
template <typename HeadT, typename... TailT>
struct TupleTrait<std::tuple<HeadT, TailT...>>
{
using Head = HeadT;
using Tail = std::tuple<TailT...>;
static constexpr size_t count = 1 + sizeof...(TailT);
template <size_t i>
using Arg = typename std::tuple_element<i, std::tuple<HeadT, TailT...>>::type;
};
template <>
struct TupleTrait<std::tuple<>>
{
using Tail = std::tuple<>;
static constexpr size_t count = 0;
};
template <typename Func, typename Enable = void>
struct FunctionTrait;
template <typename Ret, typename... Args>
struct FunctionTrait<Ret (*)(Args...)>
{
using ReturnType = Ret;
using Arguments = std::tuple<Args...>;
};
template <typename C, typename Ret, typename... Args>
struct FunctionTrait<Ret (C::*)(Args...)> : FunctionTrait<Ret (*)(Args...)>
{
};
template <typename C, typename Ret, typename... Args>
struct FunctionTrait<Ret (C::*)(Args...) const> : FunctionTrait<Ret (*)(Args...)>
{
};
template <typename C, typename Ret, typename... Args>
struct FunctionTrait<Ret (C::*)(Args...) volatile> : FunctionTrait<Ret (*)(Args...)>
{
};
template <typename C, typename Ret, typename... Args>
struct FunctionTrait<Ret (C::*)(Args...) const volatile> : FunctionTrait<Ret (*)(Args...)>
{
};
// functor and lambda
template <typename Functor>
struct FunctionTrait<Functor, Void_t<decltype(&Functor::operator())>>
{
private:
using FunctorTrait = FunctionTrait<decltype(&Functor::operator())>;
public:
using ReturnType = typename FunctorTrait::ReturnType;
using Arguments = typename TupleTrait<typename FunctorTrait::Arguments>::Tail;
};
// decay: remove const, reference; function type to function pointer
template <typename Func>
struct FunctionTrait<Func, typename std::enable_if<!std::is_same<Func, typename std::decay<Func>::type>::value>::type>
: FunctionTrait<typename std::decay<Func>::type>
{
};
} // namespace traits
template <typename API, std::size_t, std::size_t, typename...>
struct ArgumentChecker
{
static bool Check(typename API::CallbackInfoType Info, typename API::ContextType Context)
{
return true;
}
};
template <typename API, std::size_t Pos, std::size_t StopPos, typename ArgType, typename... Rest>
struct ArgumentChecker<API, Pos, StopPos, ArgType, Rest...>
{
static constexpr int NextPos = Pos + 1;
template <typename T>
using DecayTypeConverter = typename API::template Converter<typename ConverterDecay<T>::type>;
static bool Check(typename API::CallbackInfoType Info, typename API::ContextType Context)
{
if (Pos >= StopPos)
return true;
if (!DecayTypeConverter<ArgType>::accept(Context, API::GetArg(Info, Pos)))
{
return false;
}
return ArgumentChecker<API, NextPos, StopPos, Rest...>::Check(Info, Context);
}
};
template <typename API, typename Enable = void>
struct ExceptionHandle;
template <typename API>
struct ExceptionHandle<API, typename std::enable_if<std::is_pointer<typename API::CallbackInfoType>::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 <typename API>
struct ExceptionHandle<API, typename std::enable_if<!std::is_pointer<typename API::CallbackInfoType>::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<typename API::CallbackInfoType>::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<typename API::CallbackInfoType>::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<typename API::CallbackInfoType>::type* pinfo = nullptr;
// throw
TripleOp(*pinfo, error_msg, false);
#else
throw UserException(error_msg);
#endif
#endif
}
};
template <typename, typename, bool, bool, bool, bool>
struct FuncCallHelper
{
};
template <typename API, typename Ret, typename... Args, bool CheckArguments, bool ReturnByPointer, bool ScriptTypePtrAsRef,
bool GetSelfFromData>
struct FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, CheckArguments, ReturnByPointer, ScriptTypePtrAsRef,
GetSelfFromData>
{
private:
template <bool Enable, std::size_t ND, typename... CArgs>
struct ArgumentsChecker;
template <typename T>
using DecayTypeConverter = typename API::template Converter<typename ConverterDecay<T>::type>;
template <std::size_t ND, typename... CArgs>
struct ArgumentsChecker<true, ND, CArgs...>
{
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<API, 0, ArgsLength - ND, CArgs...>::Check(info, context))
return false;
return true;
}
};
template <std::size_t ND, typename... CArgs>
struct ArgumentsChecker<false, ND, CArgs...>
{
static constexpr auto ArgsLength = sizeof...(CArgs);
static bool Check(typename API::ContextType context, typename API::CallbackInfoType info)
{
return true;
}
};
template <typename T, typename = void>
struct ArgumentType
{
using type = typename std::decay<T>::type;
};
template <typename T>
struct ArgumentType<T, typename std::enable_if<(is_objecttype<typename std::decay<T>::type>::value ||
is_uetype<typename std::decay<T>::type>::value) &&
std::is_lvalue_reference<T>::value>::type>
{
using type = std::reference_wrapper<typename std::decay<T>::type>;
};
static constexpr auto ArgsLength = sizeof...(Args);
template <typename T, typename Enable = void>
struct ReturnConverter
{
static typename API::ValueType Convert(typename API::ContextType context, T ret)
{
return DecayTypeConverter<typename std::remove_reference<T>::type>::toScript(context, std::forward<T>(ret));
}
};
template <typename T>
struct ReturnConverter<T,
typename std::enable_if<(ReturnByPointer || (std::is_reference<T>::value && !std::is_const<T>::value)) &&
(is_objecttype<typename std::decay<T>::type>::value ||
is_uetype<typename std::decay<T>::type>::value)>::type>
{
static typename API::ValueType Convert(typename API::ContextType context, const typename std::decay<T>::type& ret)
{
return DecayTypeConverter<typename std::decay<T>::type*>::toScript(
context, &(const_cast<typename std::decay<T>::type&>(ret)));
}
};
template <typename T, typename Enable = void>
struct ArgumentHolder
{
typename ArgumentType<T>::type Arg;
using ArgumentDecayType = typename std::decay<T>::type;
ArgumentHolder(std::tuple<typename API::ContextType, typename API::ValueType> info)
: Arg(DecayTypeConverter<ArgumentDecayType>::toCpp(std::get<0>(info), std::get<1>(info)))
{
}
typename ArgumentType<T>::type& GetArgument()
{
return Arg;
}
void SetArgument(typename ArgumentType<T>::type InArg)
{
Arg = InArg;
}
void SetRef(typename API::ContextType context, typename API::ValueType holder)
{
}
};
template <typename T>
struct ArgumentHolder<T,
typename std::enable_if<
(is_objecttype<typename std::decay<T>::type>::value || is_uetype<typename std::decay<T>::type>::value) &&
std::is_lvalue_reference<T>::value && !std::is_const<typename std::remove_reference<T>::type>::value &&
std::is_constructible<typename std::decay<T>::type>::value &&
std::is_copy_constructible<typename std::decay<T>::type>::value &&
std::is_destructible<typename std::decay<T>::type>::value>::type>
{
typename ArgumentType<T>::type Arg;
typename ArgumentBufferType<T>::type Buf;
ArgumentHolder(std::tuple<typename API::ContextType, typename API::ValueType> info)
: Arg(*DecayTypeConverter<typename ArgumentType<T>::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<T>::type& GetArgument()
{
return Arg;
}
void SetArgument(typename ArgumentType<T>::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<typename std::decay<T>::type>::toScript(context, Arg.get()));
}
};
template <typename T>
struct ArgumentHolder<T,
typename std::enable_if<
(is_objecttype<typename std::decay<T>::type>::value || is_uetype<typename std::decay<T>::type>::value) &&
std::is_lvalue_reference<T>::value && !std::is_const<typename std::remove_reference<T>::type>::value &&
(!std::is_constructible<typename std::decay<T>::type>::value ||
!std::is_copy_constructible<typename std::decay<T>::type>::value ||
!std::is_destructible<typename std::decay<T>::type>::value)>::type>
{
typename ArgumentType<T>::type Arg;
// there may be nullptr ref
ArgumentHolder(std::tuple<typename API::ContextType, typename API::ValueType> info)
: Arg(*DecayTypeConverter<typename ArgumentType<T>::type>::toCpp(std::get<0>(info), std::get<1>(info)))
{
}
typename ArgumentType<T>::type& GetArgument()
{
return Arg;
}
void SetArgument(typename ArgumentType<T>::type InArg)
{
Arg = InArg;
}
void SetRef(typename API::ContextType context, typename API::ValueType holder)
{
}
};
template <typename T>
struct ArgumentHolder<T,
typename std::enable_if<
(is_objecttype<typename std::decay<T>::type>::value || is_uetype<typename std::decay<T>::type>::value) &&
std::is_lvalue_reference<T>::value && std::is_const<typename std::remove_reference<T>::type>::value>::type>
{
typename ArgumentType<T>::type Arg;
// there may be nullptr ref
ArgumentHolder(std::tuple<typename API::ContextType, typename API::ValueType> info)
: Arg(*DecayTypeConverter<typename std::decay<T>::type*>::toCpp(std::get<0>(info), std::get<1>(info)))
{
}
typename ArgumentType<T>::type& GetArgument()
{
return Arg;
}
using BuffType = typename std::remove_const<typename std::remove_reference<T>::type>::type;
BuffType Buf;
void SetArgument(BuffType InArg)
{
Buf = InArg;
Arg = Buf;
}
void SetRef(typename API::ContextType context, typename API::ValueType holder)
{
}
};
template <typename T>
struct ArgumentHolder<T,
typename std::enable_if<!is_objecttype<typename std::decay<T>::type>::value &&
!is_uetype<typename std::decay<T>::type>::value && std::is_lvalue_reference<T>::value &&
!std::is_const<typename std::remove_reference<T>::type>::value>::type>
{
typename ArgumentType<T>::type Arg;
using ArgumentDecayType = typename std::decay<T>::type;
ArgumentHolder(std::tuple<typename API::ContextType, typename API::ValueType> info)
: Arg(DecayTypeConverter<std::reference_wrapper<ArgumentDecayType>>::toCpp(std::get<0>(info), std::get<1>(info)))
{
}
typename ArgumentType<T>::type& GetArgument()
{
return Arg;
}
void SetArgument(typename ArgumentType<T>::type InArg)
{
Arg = InArg;
}
void SetRef(typename API::ContextType context, typename API::ValueType holder)
{
API::UpdateRefValue(context, holder, API::template Converter<typename std::decay<T>::type>::toScript(context, Arg));
}
};
template <typename T>
struct ArgumentHolder<T,
typename std::enable_if<ScriptTypePtrAsRef &&
is_script_type<typename std::remove_const<typename std::remove_pointer<T>::type>::type>::value &&
!API::template CustomArgumentBufferType<T>::enable && std::is_pointer<T>::value>::type>
{
T Arg = nullptr;
using BuffType = typename std::remove_const<typename std::remove_pointer<T>::type>::type;
BuffType Buf;
ArgumentHolder(std::tuple<typename API::ContextType, typename API::ValueType> info)
: Buf(DecayTypeConverter<std::reference_wrapper<BuffType>>::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<BuffType>::toScript(context, Buf));
}
};
template <typename T>
struct ArgumentHolder<T,
typename std::enable_if<!ScriptTypePtrAsRef &&
is_script_type<typename std::remove_const<typename std::remove_pointer<T>::type>::type>::value &&
!API::template CustomArgumentBufferType<T>::enable && std::is_pointer<T>::value>::type>
{
T Arg = nullptr;
ArgumentHolder(std::tuple<typename API::ContextType, typename API::ValueType> info)
: Arg(DecayTypeConverter<T>::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 <typename T>
struct ArgumentHolder<T, typename std::enable_if<API::template CustomArgumentBufferType<T>::enable>::type>
{
typename ArgumentType<T>::type Arg;
typename API::template CustomArgumentBufferType<T>::type Buf;
ArgumentHolder(std::tuple<typename API::ContextType, typename API::ValueType> info)
: Buf(std::get<0>(info), std::get<1>(info))
{
Arg = Buf.Data();
}
typename ArgumentType<T>::type GetArgument()
{
return Arg;
}
void SetArgument(typename ArgumentType<T>::type InArg)
{
Arg = InArg;
}
void SetRef(typename API::ContextType context, typename API::ValueType holder)
{
}
};
using ArgumentsHolder = std::tuple<ArgumentHolder<Args>...>;
template <int, typename...>
struct RefValuesSync
{
static void Sync(typename API::ContextType context, typename API::CallbackInfoType info, ArgumentsHolder& cppArgHolders)
{
}
};
template <int Pos, typename T, typename... Rest>
struct RefValuesSync<Pos, T, Rest...>
{
static void Sync(typename API::ContextType context, typename API::CallbackInfoType info, ArgumentsHolder& cppArgHolders)
{
std::get<Pos>(cppArgHolders).SetRef(context, API::GetArg(info, Pos));
RefValuesSync<Pos + 1, Rest...>::Sync(context, info, cppArgHolders);
}
};
template <int Skip, int Pos, typename... FullArgs>
struct DefaultValueSetter;
template <int Skip, int Pos, typename T, typename... FullArgs>
struct DefaultValueSetter<Skip, Pos, T, FullArgs...> : DefaultValueSetter<Skip - 1, Pos + 1, FullArgs...>
{
};
template <int Pos, typename T, typename... FullArgs>
struct DefaultValueSetter<0, Pos, T, FullArgs...>
{
template <class T1, class... DefaultArguments>
static void Set(ArgumentsHolder& cppArgHolders, int argCount, T1 defaultValue, const DefaultArguments&... rest)
{
if (argCount <= Pos)
{
std::get<Pos>(cppArgHolders).SetArgument(defaultValue);
}
DefaultValueSetter<0, Pos + 1, FullArgs...>::Set(cppArgHolders, argCount, rest...);
}
};
template <int Pos>
struct DefaultValueSetter<0, Pos>
{
static void Set(ArgumentsHolder& cppArgHolders, int argCount)
{
}
};
template <typename Func, size_t... index, class... DefaultArguments>
static
typename std::enable_if<std::is_same<typename internal::traits::FunctionTrait<Func>::ReturnType, void>::value, bool>::type
call(Func& func, typename API::CallbackInfoType info, std::index_sequence<index...>, DefaultArguments&&... defaultValues)
{
auto context = API::GetContext(info);
if (!ArgumentsChecker<CheckArguments, sizeof...(DefaultArguments), Args...>::Check(context, info))
return false;
ArgumentsHolder cppArgHolders(
std::tuple<typename API::ContextType, typename API::ValueType>{context, API::GetArg(info, index)}...);
DefaultValueSetter<sizeof...(Args) - sizeof...(DefaultArguments), 0, typename std::decay<Args>::type...>::Set(
cppArgHolders, API::GetArgsLen(info), std::forward<DefaultArguments>(defaultValues)...);
func(std::forward<Args>(std::get<index>(cppArgHolders).GetArgument())...);
RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders);
return true;
}
template <typename Func, size_t... index, class... DefaultArguments>
static
typename std::enable_if<!std::is_same<typename internal::traits::FunctionTrait<Func>::ReturnType, void>::value, bool>::type
call(Func& func, typename API::CallbackInfoType info, std::index_sequence<index...>, DefaultArguments&&... defaultValues)
{
auto context = API::GetContext(info);
if (!ArgumentsChecker<CheckArguments, sizeof...(DefaultArguments), Args...>::Check(context, info))
return false;
ArgumentsHolder cppArgHolders(
std::tuple<typename API::ContextType, typename API::ValueType>{context, API::GetArg(info, index)}...);
DefaultValueSetter<sizeof...(Args) - sizeof...(DefaultArguments), 0, typename std::decay<Args>::type...>::Set(
cppArgHolders, API::GetArgsLen(info), std::forward<DefaultArguments>(defaultValues)...);
API::SetReturn(info, ReturnConverter<Ret>::Convert(context,
std::forward<Ret>(func(std::forward<Args>(std::get<index>(cppArgHolders).GetArgument())...))));
RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders);
return true;
}
template <bool, typename Ins>
struct SelfGetter;
template <typename Ins>
struct SelfGetter<false, Ins>
{
static Ins* Get(typename API::ContextType context, typename API::CallbackInfoType info)
{
return DecayTypeConverter<Ins*>::toCpp(context, API::GetHolder(info));
}
};
template <typename Ins>
struct SelfGetter<true, Ins>
{
static Ins* Get(typename API::ContextType context, typename API::CallbackInfoType info)
{
return static_cast<Ins*>(API::GetFunctionData(info));
}
};
template <typename Ins, typename Func, size_t... index, class... DefaultArguments>
static
typename std::enable_if<std::is_same<typename internal::traits::FunctionTrait<Func>::ReturnType, void>::value, bool>::type
callMethod(
Func& func, typename API::CallbackInfoType info, std::index_sequence<index...>, DefaultArguments&&... defaultValues)
{
auto context = API::GetContext(info);
auto self = SelfGetter<GetSelfFromData, Ins>::Get(context, info);
if (!self)
{
API::ThrowException(info, "access a null object");
return true;
}
if (!ArgumentsChecker<CheckArguments, sizeof...(DefaultArguments), Args...>::Check(context, info))
return false;
ArgumentsHolder cppArgHolders(
std::tuple<typename API::ContextType, typename API::ValueType>{context, API::GetArg(info, index)}...);
DefaultValueSetter<sizeof...(Args) - sizeof...(DefaultArguments), 0, typename std::decay<Args>::type...>::Set(
cppArgHolders, API::GetArgsLen(info), std::forward<DefaultArguments>(defaultValues)...);
(self->*func)(std::forward<Args>(std::get<index>(cppArgHolders).GetArgument())...);
RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders);
return true;
}
template <typename Ins, typename Func, size_t... index, class... DefaultArguments>
static
typename std::enable_if<!std::is_same<typename internal::traits::FunctionTrait<Func>::ReturnType, void>::value, bool>::type
callMethod(
Func& func, typename API::CallbackInfoType info, std::index_sequence<index...>, DefaultArguments&&... defaultValues)
{
auto context = API::GetContext(info);
auto self = SelfGetter<GetSelfFromData, Ins>::Get(context, info);
if (!self)
{
API::ThrowException(info, "access a null object");
return true;
}
if (!ArgumentsChecker<CheckArguments, sizeof...(DefaultArguments), Args...>::Check(context, info))
return false;
ArgumentsHolder cppArgHolders(
std::tuple<typename API::ContextType, typename API::ValueType>{context, API::GetArg(info, index)}...);
DefaultValueSetter<sizeof...(Args) - sizeof...(DefaultArguments), 0, typename std::decay<Args>::type...>::Set(
cppArgHolders, API::GetArgsLen(info), std::forward<DefaultArguments>(defaultValues)...);
API::SetReturn(
info, ReturnConverter<Ret>::Convert(context,
std::forward<Ret>((self->*func)(std::forward<Args>(std::get<index>(cppArgHolders).GetArgument())...))));
RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders);
return true;
}
template <typename Ins, typename Func, size_t... index, class... DefaultArguments>
static
typename std::enable_if<std::is_same<typename internal::traits::FunctionTrait<Func>::ReturnType, void>::value, bool>::type
callExtension(
Func& func, typename API::CallbackInfoType info, std::index_sequence<index...>, DefaultArguments&&... defaultValues)
{
auto context = API::GetContext(info);
auto self = DecayTypeConverter<Ins*>::toCpp(context, API::GetHolder(info));
if (!self)
{
API::ThrowException(info, "access a null object");
return true;
}
if (!ArgumentsChecker<CheckArguments, sizeof...(DefaultArguments), Args...>::Check(context, info))
return false;
ArgumentsHolder cppArgHolders(
std::tuple<typename API::ContextType, typename API::ValueType>{context, API::GetArg(info, index)}...);
DefaultValueSetter<sizeof...(Args) - sizeof...(DefaultArguments), 0, typename std::decay<Args>::type...>::Set(
cppArgHolders, API::GetArgsLen(info), std::forward<DefaultArguments>(defaultValues)...);
func(*self, std::forward<Args>(std::get<index>(cppArgHolders).GetArgument())...);
RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders);
return true;
}
template <typename Ins, typename Func, size_t... index, class... DefaultArguments>
static
typename std::enable_if<!std::is_same<typename internal::traits::FunctionTrait<Func>::ReturnType, void>::value, bool>::type
callExtension(
Func& func, typename API::CallbackInfoType info, std::index_sequence<index...>, DefaultArguments&&... defaultValues)
{
auto context = API::GetContext(info);
auto self = DecayTypeConverter<Ins*>::toCpp(context, API::GetHolder(info));
if (!self)
{
API::ThrowException(info, "access a null object");
return true;
}
if (!ArgumentsChecker<CheckArguments, sizeof...(DefaultArguments), Args...>::Check(context, info))
return false;
ArgumentsHolder cppArgHolders(
std::tuple<typename API::ContextType, typename API::ValueType>{context, API::GetArg(info, index)}...);
DefaultValueSetter<sizeof...(Args) - sizeof...(DefaultArguments), 0, typename std::decay<Args>::type...>::Set(
cppArgHolders, API::GetArgsLen(info), std::forward<DefaultArguments>(defaultValues)...);
API::SetReturn(
info, ReturnConverter<Ret>::Convert(context,
std::forward<Ret>(func(*self, std::forward<Args>(std::get<index>(cppArgHolders).GetArgument())...))));
RefValuesSync<0, Args...>::Sync(context, info, cppArgHolders);
return true;
}
public:
template <typename Func, class... DefaultArguments>
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<API>::TripleOp(info, nullptr, false);
#endif
#endif
return call(func, info, std::make_index_sequence<ArgsLength>(), std::forward<DefaultArguments>(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 <typename Ins, typename Func, class... DefaultArguments>
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<API>::TripleOp(info, nullptr, false);
#endif
#endif
return callMethod<Ins>(
func, info, std::make_index_sequence<ArgsLength>(), std::forward<DefaultArguments>(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 <typename Ins, typename Func, class... DefaultArguments>
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<API>::TripleOp(info, nullptr, false);
#endif
#endif
return callExtension<Ins>(
func, info, std::make_index_sequence<ArgsLength>(), std::forward<DefaultArguments>(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 <typename API, typename T, T, bool ReturnByPointer = false, bool ScriptTypePtrAsRef = true, bool GetSelfFromData = false>
struct FuncCallWrapper;
template <typename API, typename Ret, typename... Args, Ret (*func)(Args...), bool ReturnByPointer, bool ScriptTypePtrAsRef,
bool GetSelfFromData>
struct FuncCallWrapper<API, Ret (*)(Args...), func, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>
{
static void call(typename API::CallbackInfoType info)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, false, ReturnByPointer,
ScriptTypePtrAsRef, GetSelfFromData>;
Helper::call(func, info);
}
static bool overloadCall(typename API::CallbackInfoType info)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, true, ReturnByPointer, ScriptTypePtrAsRef,
GetSelfFromData>;
return Helper::call(func, info);
}
static void checkedCall(typename API::CallbackInfoType info)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, true, ReturnByPointer, ScriptTypePtrAsRef,
GetSelfFromData>;
if (!Helper::call(func, info))
{
API::ThrowException(info, "invalid parameter!");
}
}
template <class... DefaultArguments>
static void callWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, false, ReturnByPointer,
ScriptTypePtrAsRef, GetSelfFromData>;
Helper::call(func, info, std::forward<DefaultArguments>(defaultValues)...);
}
template <class... DefaultArguments>
static bool overloadCallWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, true, ReturnByPointer, ScriptTypePtrAsRef,
GetSelfFromData>;
return Helper::call(func, info, std::forward<DefaultArguments>(defaultValues)...);
}
static const CFunctionInfo* info(unsigned int defaultCount = 0)
{
return CFunctionInfoByPtrImpl<Ret (*)(Args...), func, ScriptTypePtrAsRef>::get(defaultCount);
}
template <typename FirstType, typename... RestTypes>
struct ExtensionCallHelper
{
template <class... DefaultArguments>
static void call(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues)
{
using FirstDecayType = typename std::decay<FirstType>::type;
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<RestTypes...>>, false, ReturnByPointer,
ScriptTypePtrAsRef, GetSelfFromData>;
Helper::template callExtension<FirstDecayType>(func, info, std::forward<DefaultArguments>(defaultValues)...);
}
};
template <class... DefaultArguments>
static void callExtensionWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues)
{
ExtensionCallHelper<Args...>::call(info, std::forward<DefaultArguments>(defaultValues)...);
}
static const CFunctionInfo* extensionInfo(unsigned int defaultCount = 0)
{
return CFunctionInfoByPtrImpl<Ret (*)(Args...), func, ScriptTypePtrAsRef, 1>::get(defaultCount);
}
};
template <typename API, typename Inc, typename Ret, typename... Args, Ret (Inc::*func)(Args...), bool ReturnByPointer,
bool ScriptTypePtrAsRef, bool GetSelfFromData>
struct FuncCallWrapper<API, Ret (Inc::*)(Args...), func, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>
{
static void call(typename API::CallbackInfoType info)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, false, ReturnByPointer,
ScriptTypePtrAsRef, GetSelfFromData>;
Helper::template callMethod<Inc>(func, info);
}
static bool overloadCall(typename API::CallbackInfoType info)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, true, ReturnByPointer, ScriptTypePtrAsRef,
GetSelfFromData>;
return Helper::template callMethod<Inc, decltype(func)>(func, info);
}
static void checkedCall(typename API::CallbackInfoType info)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, true, ReturnByPointer, ScriptTypePtrAsRef,
GetSelfFromData>;
if (!Helper::template callMethod<Inc, decltype(func)>(func, info))
{
API::ThrowException(info, "invalid parameter!");
}
}
template <class... DefaultArguments>
static void callWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, false, ReturnByPointer,
ScriptTypePtrAsRef, GetSelfFromData>;
Helper::template callMethod<Inc>(func, info, std::forward<DefaultArguments>(defaultValues)...);
}
template <class... DefaultArguments>
static bool overloadCallWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, true, ReturnByPointer, ScriptTypePtrAsRef,
GetSelfFromData>;
return Helper::template callMethod<Inc>(func, info, std::forward<DefaultArguments>(defaultValues)...);
}
static const CFunctionInfo* info(unsigned int defaultCount = 0)
{
return CFunctionInfoByPtrImpl<Ret (Inc::*)(Args...), func, ScriptTypePtrAsRef>::get(defaultCount);
}
};
// TODO: Similar logic...
template <typename API, typename Inc, typename Ret, typename... Args, Ret (Inc::*func)(Args...) const, bool ReturnByPointer,
bool ScriptTypePtrAsRef, bool GetSelfFromData>
struct FuncCallWrapper<API, Ret (Inc::*)(Args...) const, func, ReturnByPointer, ScriptTypePtrAsRef, GetSelfFromData>
{
static void call(typename API::CallbackInfoType info)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, false, ReturnByPointer,
ScriptTypePtrAsRef, GetSelfFromData>;
Helper::template callMethod<Inc>(func, info);
}
static bool overloadCall(typename API::CallbackInfoType info)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, true, ReturnByPointer, ScriptTypePtrAsRef,
GetSelfFromData>;
return Helper::template callMethod<Inc, decltype(func)>(func, info);
}
static void checkedCall(typename API::CallbackInfoType info)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, true, ReturnByPointer, ScriptTypePtrAsRef,
GetSelfFromData>;
if (!Helper::template callMethod<Inc, decltype(func)>(func, info))
{
API::ThrowException(info, "invalid parameter!");
}
}
template <class... DefaultArguments>
static void callWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, false, ReturnByPointer,
ScriptTypePtrAsRef, GetSelfFromData>;
Helper::template callMethod<Inc>(func, info, std::forward<DefaultArguments>(defaultValues)...);
}
template <class... DefaultArguments>
static bool overloadCallWithDefaultValues(typename API::CallbackInfoType info, DefaultArguments&&... defaultValues)
{
using Helper = internal::FuncCallHelper<API, std::pair<Ret, std::tuple<Args...>>, true, ReturnByPointer, ScriptTypePtrAsRef,
GetSelfFromData>;
return Helper::template callMethod<Inc>(func, info, std::forward<DefaultArguments>(defaultValues)...);
}
static const CFunctionInfo* info(unsigned int defaultCount = 0)
{
return CFunctionInfoByPtrImpl<Ret (Inc::*)(Args...) const, func, ScriptTypePtrAsRef>::get(defaultCount);
}
};
template <typename API, typename T, typename... Args>
struct ConstructorWrapper
{
private:
template <typename CT>
using DecayTypeConverter = typename API::template Converter<typename internal::ConverterDecay<CT>::type>;
static constexpr auto ArgsLength = sizeof...(Args);
template <class FT, typename Enable = void>
struct Finalize
{
static void Do(const FT*)
{
}
};
template <class FT>
struct Finalize<FT, typename std::enable_if<std::is_destructible<FT>::value>::type>
{
static void Do(const FT* Ptr)
{
delete Ptr;
}
};
template <size_t... index>
static void* call(typename API::CallbackInfoType info, std::index_sequence<index...>)
{
auto context = API::GetContext(info);
if (API::GetArgsLen(info) != ArgsLength)
{
return nullptr;
}
if (!internal::ArgumentChecker<API, 0, ArgsLength, Args...>::Check(info, context))
{
return nullptr;
}
#if defined(WITH_THROW_IN_CPP) && defined(THREAD_LOCAL_IMPL_THROW)
internal::ExceptionHandle<API>::TripleOp(info, nullptr, false);
#endif
T* obj = new T(DecayTypeConverter<Args>::toCpp(context, API::GetArg(info, index))...);
#if defined(WITH_THROW_IN_CPP) && defined(THREAD_LOCAL_IMPL_THROW)
// get state
if (internal::ExceptionHandle<API>::TripleOp(info, nullptr, true))
{
Finalize<T>::Do(obj);
obj = nullptr;
}
#endif
return obj;
}
public:
static void* call(typename API::CallbackInfoType info)
{
return call(info, std::make_index_sequence<ArgsLength>());
}
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<API>::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<T, true, 0, Args...>::get(defaultCount);
}
};
template <typename API, typename... OverloadWraps>
struct ConstructorsCombiner
{
template <typename API::InitializeFuncType Func, typename API::InitializeFuncType... Rest>
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<API>::TripleOp(info, nullptr, true))
{
return Ret;
}
#endif
// try next overload
return ConstructorRecursion<Rest...>::_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<API>::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 <typename API::InitializeFuncType Func>
struct ConstructorRecursion<Func>
{
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 <typename API, typename... OverloadWraps>
struct OverloadsCombiner
{
typedef bool (*V8FunctionCallbackWithBoolRet)(typename API::CallbackInfoType info);
template <V8FunctionCallbackWithBoolRet Func, V8FunctionCallbackWithBoolRet... Rest>
struct OverloadsRecursion
{
static bool _call(typename API::CallbackInfoType info)
{
if (Func(info))
return true;
else
return OverloadsRecursion<Rest...>::_call(info);
}
static void call(typename API::CallbackInfoType info)
{
if (!_call(info))
{
API::ThrowException(info, "invalid parameter!");
}
}
};
template <V8FunctionCallbackWithBoolRet Func>
struct OverloadsRecursion<Func>
{
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 <class T>
struct IsBoundedArray : std::false_type
{
};
template <class T, std::size_t N>
struct IsBoundedArray<T[N]> : std::true_type
{
};
template <typename API, typename T, T, typename IncPass = void, typename Enable = void>
struct PropertyWrapper;
template <typename API, class Ins, class Ret, Ret Ins::*member, typename IncPass>
struct PropertyWrapper<API, Ret Ins::*, member, IncPass,
typename std::enable_if<!is_objecttype<Ret>::value && !is_uetype<Ret>::value && !IsBoundedArray<Ret>::value>::type>
{
template <typename T>
using DecayTypeConverter = typename API::template Converter<typename internal::ConverterDecay<T>::type>;
using SelfType = typename std::conditional<std::is_same<IncPass, void>::value, Ins, IncPass>::type;
static void getter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
auto self = DecayTypeConverter<SelfType*>::toCpp(context, API::GetThis(info));
if (!self)
{
API::ThrowException(info, "access a null object");
return;
}
API::SetReturn(info, DecayTypeConverter<Ret>::toScript(context, self->*member));
}
static void setter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
auto self = DecayTypeConverter<SelfType*>::toCpp(context, API::GetThis(info));
if (!self)
{
API::ThrowException(info, "access a null object");
return;
}
self->*member = DecayTypeConverter<Ret>::toCpp(context, API::GetArg(info, 0));
}
static const CTypeInfo* info()
{
return CTypeInfoImpl<Ret, false>::get();
}
};
template <typename API, class Ins, class Ret, Ret Ins::*member, typename IncPass>
struct PropertyWrapper<API, Ret Ins::*, member, IncPass,
typename std::enable_if<!is_objecttype<Ret>::value && !is_uetype<Ret>::value && IsBoundedArray<Ret>::value>::type>
{
template <typename T>
using DecayTypeConverter = typename API::template Converter<typename internal::ConverterDecay<T>::type>;
using SelfType = typename std::conditional<std::is_same<IncPass, void>::value, Ins, IncPass>::type;
static void getter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
auto self = DecayTypeConverter<SelfType*>::toCpp(context, API::GetThis(info));
if (!self)
{
API::ThrowException(info, "access a null object");
return;
}
API::SetReturn(info, API::template Converter<Ret>::toScript(context, self->*member));
}
static void setter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
auto self = DecayTypeConverter<SelfType*>::toCpp(context, API::GetThis(info));
if (!self)
{
API::ThrowException(info, "access a null object");
return;
}
if (!API::template Converter<Ret>::accept(context, API::GetArg(info, 0)))
{
API::ThrowException(info, "invalid value for property");
return;
}
auto Src = DecayTypeConverter<Ret>::toCpp(context, API::GetArg(info, 0));
if (self->*member == Src)
{
return;
}
memcpy(self->*member, Src, sizeof(Ret));
}
static const CTypeInfo* info()
{
return CTypeInfoImpl<Ret, false>::get();
}
};
template <typename API, class Ins, class Ret, Ret Ins::*member, typename IncPass>
struct PropertyWrapper<API, Ret Ins::*, member, IncPass,
typename std::enable_if<is_objecttype<Ret>::value || is_uetype<Ret>::value>::type>
{
template <typename T>
using DecayTypeConverter = typename API::template Converter<typename internal::ConverterDecay<T>::type>;
using SelfType = typename std::conditional<std::is_same<IncPass, void>::value, Ins, IncPass>::type;
static void getter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
auto self = DecayTypeConverter<SelfType*>::toCpp(context, API::GetThis(info));
if (!self)
{
API::ThrowException(info, "access a null object");
return;
}
auto ret = DecayTypeConverter<Ret*>::toScript(context, &(self->*member));
API::template LinkOuter<Ins, Ret>(context, API::GetThis(info), ret);
API::SetReturn(info, ret);
}
static void setter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
auto self = DecayTypeConverter<SelfType*>::toCpp(context, API::GetThis(info));
if (!self)
{
API::ThrowException(info, "access a null object");
return;
}
self->*member = DecayTypeConverter<Ret>::toCpp(context, API::GetArg(info, 0));
}
static const CTypeInfo* info()
{
return CTypeInfoImpl<Ret, false>::get();
}
};
template <typename API, typename Ret, Ret* Variable>
struct PropertyWrapper<API, Ret*, Variable>
{
template <typename T>
using DecayTypeConverter = typename API::template Converter<typename internal::ConverterDecay<T>::type>;
static void getter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
API::SetReturn(info, DecayTypeConverter<Ret>::toScript(context, *Variable));
}
static void setter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
*Variable = DecayTypeConverter<Ret>::toCpp(context, API::GetArg(info, 0));
}
static const CTypeInfo* info()
{
return CTypeInfoImpl<Ret, false>::get();
}
};
template <typename API, typename TG, TG, typename Enable = void>
struct PropertyGetterWrapper;
template <typename API, typename Ret, Ret (*fgetter)()>
struct PropertyGetterWrapper<API, Ret (*)(), fgetter>
{
template <typename T>
using DecayTypeConverter = typename API::template Converter<typename internal::ConverterDecay<T>::type>;
static void getter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
API::SetReturn(info, DecayTypeConverter<Ret>::toScript(context, fgetter()));
}
};
template <typename API, typename Ret, typename Ins, Ret (Ins::*func)()>
struct PropertyGetterWrapper<API, Ret (Ins::*)(), func>
{
template <typename T>
using DecayTypeConverter = typename API::template Converter<typename internal::ConverterDecay<T>::type>;
static void getter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
auto self = DecayTypeConverter<Ins*>::toCpp(context, API::GetThis(info));
if (!self)
{
API::ThrowException(info, "access a null object");
return;
}
API::SetReturn(info, API::template Converter<Ret>::toScript(context, (self->*func)()));
}
};
template <typename API, typename Ret, typename Ins, Ret (Ins::*func)() const>
struct PropertyGetterWrapper<API, Ret (Ins::*)() const, func>
{
template <typename T>
using DecayTypeConverter = typename API::template Converter<typename internal::ConverterDecay<T>::type>;
static void getter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
auto self = DecayTypeConverter<Ins*>::toCpp(context, API::GetThis(info));
if (!self)
{
API::ThrowException(info, "access a null object");
return;
}
API::SetReturn(info, API::template Converter<Ret>::toScript(context, (self->*func)()));
}
};
template <typename API>
struct PropertyGetterWrapper<API, decltype(nullptr), nullptr>
{
static void getter(typename API::CallbackInfoType info)
{
API::ThrowException(info, "not getter for this property!");
}
};
template <typename API, typename TS, TS, typename Enable = void>
struct PropertySetterWrapper;
template <typename API, typename TS, void (*fsetter)(TS)>
struct PropertySetterWrapper<API, void (*)(TS), fsetter>
{
template <typename T>
using DecayTypeConverter = typename API::template Converter<typename internal::ConverterDecay<T>::type>;
static void setter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
fsetter(DecayTypeConverter<TS>::toCpp(context, API::GetArg(info, 0)));
}
};
template <typename API, typename TS, typename Ins, void (Ins::*func)(TS)>
struct PropertySetterWrapper<API, void (Ins::*)(TS), func>
{
template <typename T>
using DecayTypeConverter = typename API::template Converter<typename internal::ConverterDecay<T>::type>;
static void setter(typename API::CallbackInfoType info)
{
auto context = API::GetContext(info);
auto self = DecayTypeConverter<Ins*>::toCpp(context, API::GetThis(info));
if (!self)
{
API::ThrowException(info, "access a null object");
return;
}
(self->*func)(DecayTypeConverter<TS>::toCpp(context, API::GetArg(info, 0)));
}
};
template <typename API>
struct PropertySetterWrapper<API, decltype(nullptr), nullptr>
{
static void setter(typename API::CallbackInfoType info)
{
API::ThrowException(info, "not setter for this property!");
}
};
template <typename API, typename TG, typename TS>
struct PropertyGetterSetterInfo;
template <typename API, typename Ret, typename TS>
struct PropertyGetterSetterInfo<API, Ret (*)(), TS>
{
static const CTypeInfo* info()
{
return CTypeInfoImpl<Ret, false>::get();
}
};
template <typename API, typename Ins, typename Ret, typename TS>
struct PropertyGetterSetterInfo<API, Ret (Ins::*)(), TS>
{
static const CTypeInfo* info()
{
return CTypeInfoImpl<Ret, false>::get();
}
};
template <typename API, typename Ins, typename Ret, typename TS>
struct PropertyGetterSetterInfo<API, Ret (Ins::*)() const, TS>
{
static const CTypeInfo* info()
{
return CTypeInfoImpl<Ret, false>::get();
}
};
template <typename API, typename Ret, typename TG>
struct PropertyGetterSetterInfo<API, TG, void (*)(Ret)>
{
static const CTypeInfo* info()
{
return CTypeInfoImpl<Ret, false>::get();
}
};
template <typename API, typename Ins, typename Ret, typename TG>
struct PropertyGetterSetterInfo<API, TG, void (Ins::*)(Ret)>
{
static const CTypeInfo* info()
{
return CTypeInfoImpl<Ret, false>::get();
}
};
template <typename T, typename API, typename RegisterAPI>
class ClassDefineBuilder
{
template <typename...>
using sfina = ClassDefineBuilder<T, API, RegisterAPI>&;
public:
const char* className_ = nullptr;
const void* superTypeId_ = nullptr;
std::vector<typename API::GeneralFunctionInfo> functions_{};
std::vector<typename API::GeneralFunctionInfo> methods_{};
std::vector<typename API::GeneralPropertyInfo> properties_{};
std::vector<typename API::GeneralPropertyInfo> variables_{};
typename API::InitializeFuncType constructor_{};
std::vector<typename API::GeneralFunctionReflectionInfo> constructorInfos_{};
std::vector<typename API::GeneralFunctionReflectionInfo> methodInfos_{};
std::vector<typename API::GeneralFunctionReflectionInfo> functionInfos_{};
std::vector<typename API::GeneralPropertyReflectionInfo> propertyInfos_{};
std::vector<typename API::GeneralPropertyReflectionInfo> variableInfos_{};
explicit ClassDefineBuilder(const char* className) : className_(className)
{
}
template <typename S>
ClassDefineBuilder<T, API, RegisterAPI>& Extends()
{
superTypeId_ = StaticTypeId<S>::get();
return *this;
}
template <typename... Args>
ClassDefineBuilder<T, API, RegisterAPI>& Constructor()
{
typename API::InitializeFuncType constructor = ConstructorWrapper<API, T, Args...>::checkedCall;
constructor_ = constructor;
constructorInfos_.push_back(
typename API::GeneralFunctionReflectionInfo{"constructor", ConstructorWrapper<API, T, Args...>::info()});
return *this;
}
ClassDefineBuilder<T, API, RegisterAPI>& 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<T, API, RegisterAPI>& 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<T, API, RegisterAPI>& 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<T, API, RegisterAPI>& 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<T, API, RegisterAPI>& 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 <typename Func, Func func>
ClassDefineBuilder<T, API, RegisterAPI>& MethodProxy(const char* name)
{
typename API::FunctionCallbackType proxyed = [](typename API::CallbackInfoType info) -> void
{
using Helper = internal::FuncCallHelper<API,
std::pair<typename internal::traits::FunctionTrait<Func>::ReturnType,
typename internal::traits::FunctionTrait<Func>::Arguments>,
false, false, true, false>;
Helper::template callMethod<T>(func, info);
};
methods_.push_back(typename API::GeneralFunctionInfo(name, proxyed, nullptr, nullptr));
return *this;
}
ClassDefineBuilder<T, API, RegisterAPI>& 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 <typename Prop, Prop prop>
ClassDefineBuilder<T, API, RegisterAPI>& PropertyProxy(const char* name)
{
properties_.push_back(typename API::GeneralPropertyInfo(
name, &PropertyWrapper<API, Prop, prop, T>::getter, &PropertyWrapper<API, Prop, prop, T>::setter, nullptr, nullptr));
return *this;
}
ClassDefineBuilder<T, API, RegisterAPI>& 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 <class FC, typename Enable = void>
struct FinalizeBuilder
{
static FinalizeFuncType Build()
{
return FinalizeFuncType{};
}
};
template <class FC>
struct FinalizeBuilder<FC, typename std::enable_if<std::is_destructible<FC>::value>::type>
{
static FinalizeFuncType Build()
{
return [](void* Ptr, void* ClassData, void* EnvData) { delete static_cast<FC*>(Ptr); };
}
};
void Register()
{
Register(FinalizeBuilder<T>::Build());
}
void Register(FinalizeFuncType Finalize)
{
RegisterAPI::template Register<T>(Finalize, *this);
}
};
} // namespace PUERTS_NAMESPACE