Files
MingSimulator/Plugins/Puerts/Source/JsEnv/Public/PesapiBackend.hpp
T

578 lines
18 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 <type_traits>
#include <string>
#include <cstring>
#include <functional>
#include <vector>
#include "pesapi.h"
#include "TypeInfo.hpp"
#define __DefObjectType_pesapi_impl(CLS) \
namespace PUERTS_NAMESPACE \
{ \
template <> \
struct is_objecttype<CLS> : public std::true_type \
{ \
}; \
}
#define __DefCDataPointerConverter_pesapi_impl(CLS) \
namespace PUERTS_NAMESPACE \
{ \
namespace pesapi_impl \
{ \
template <> \
struct Converter<CLS*> \
{ \
static pesapi_value toScript(pesapi_env env, CLS* value) \
{ \
return pesapi_native_object_to_value(env, DynamicTypeId<CLS>::get(value), value, false); \
} \
static CLS* toCpp(pesapi_env env, pesapi_value value) \
{ \
return static_cast<CLS*>(pesapi_get_native_object_ptr(env, value)); \
} \
static bool accept(pesapi_env env, pesapi_value value) \
{ \
return pesapi_is_instance_of(env, StaticTypeId<CLS>::get(), value); \
} \
}; \
} \
}
namespace PUERTS_NAMESPACE
{
namespace pesapi_impl
{
template <typename T, typename Enable = void>
struct Converter;
template <typename T, typename = void>
struct CustomArgumentBufferType
{
static constexpr bool enable = false;
};
struct API
{
typedef pesapi_callback_info CallbackInfoType;
typedef pesapi_env ContextType;
typedef pesapi_value ValueType;
typedef void (*FunctionCallbackType)(pesapi_callback_info info);
typedef void* (*InitializeFuncType)(pesapi_callback_info Info);
struct GeneralFunctionInfo
{
const char* Name;
FunctionCallbackType Callback;
void* Data = nullptr;
const CFunctionInfo* ReflectionInfo = nullptr;
};
struct GeneralPropertyInfo
{
const char* Name;
FunctionCallbackType Getter;
FunctionCallbackType Setter;
void* Data = nullptr;
};
typedef NamedFunctionInfo GeneralFunctionReflectionInfo;
typedef NamedPropertyInfo GeneralPropertyReflectionInfo;
inline static int GetArgsLen(pesapi_callback_info info)
{
return pesapi_get_args_len(info);
}
inline static pesapi_value GetArg(pesapi_callback_info info, int index)
{
return pesapi_get_arg(info, index);
}
inline static pesapi_env GetContext(pesapi_callback_info info)
{
return pesapi_get_env(info);
}
inline static pesapi_value GetThis(pesapi_callback_info info)
{
return pesapi_get_this(info);
}
inline static pesapi_value GetHolder(pesapi_callback_info info)
{
return pesapi_get_holder(info);
}
// use where GetSelfFromData is true
inline static void* GetFunctionData(pesapi_callback_info info)
{
return pesapi_get_userdata(info);
}
inline static void ThrowException(pesapi_callback_info info, const char* msg)
{
pesapi_throw_by_string(info, msg);
}
inline static void SetReturn(pesapi_callback_info info, pesapi_value value)
{
pesapi_add_return(info, value);
}
template <typename T1, typename T2>
inline static void LinkOuter(pesapi_env env, pesapi_value outer, pesapi_value inner)
{
pesapi_set_property_uint32(env, inner, 0, outer);
}
inline static void UpdateRefValue(pesapi_env env, pesapi_value holder, pesapi_value value)
{
if (pesapi_is_object(env, holder))
{
pesapi_update_boxed_value(env, holder, value);
}
}
template <typename T>
inline static T* FastGetNativeObjectPointer(pesapi_env env, pesapi_value value)
{
return static_cast<T*>(pesapi_get_native_object_ptr(env, value));
}
inline static pesapi_value GetUndefined(pesapi_env env)
{
return pesapi_create_undefined(env);
}
inline static bool IsNullOrUndefined(pesapi_env env, pesapi_value val)
{
return pesapi_is_null(env, val) || pesapi_is_undefined(env, val);
}
typedef void (*FinalizeFuncType)(void* Ptr);
template <typename T, typename CDB>
static void Register(FinalizeFuncType Finalize, const CDB& Cdb)
{
size_t properties_count = Cdb.functions_.size() + Cdb.methods_.size() + Cdb.properties_.size() + Cdb.variables_.size();
auto properties = pesapi_alloc_property_descriptors(properties_count);
size_t pos = 0;
for (const auto& func : Cdb.functions_)
{
pesapi_set_method_info(properties, pos++, func.Name, true, func.Callback, nullptr, nullptr);
}
for (const auto& method : Cdb.methods_)
{
pesapi_set_method_info(properties, pos++, method.Name, false, method.Callback, nullptr, nullptr);
}
for (const auto& prop : Cdb.properties_)
{
pesapi_set_property_info(properties, pos++, prop.Name, false, prop.Getter, prop.Setter, nullptr, nullptr, nullptr);
}
for (const auto& prop : Cdb.variables_)
{
pesapi_set_property_info(properties, pos++, prop.Name, true, prop.Getter, prop.Setter, nullptr, nullptr, nullptr);
}
pesapi_finalize finalize = Finalize;
pesapi_define_class(StaticTypeId<T>::get(), Cdb.superTypeId_, Cdb.className_,
reinterpret_cast<InitializeFuncType>(Cdb.constructor_), finalize, properties_count, properties, nullptr);
static std::vector<NamedFunctionInfo> s_constructorInfos_{};
static std::vector<NamedFunctionInfo> s_methodInfos_{};
static std::vector<NamedFunctionInfo> s_functionInfos_{};
static std::vector<NamedPropertyInfo> s_propertyInfos_{};
static std::vector<NamedPropertyInfo> s_variableInfos_{};
s_constructorInfos_ = std::move(Cdb.constructorInfos_);
s_constructorInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
s_methodInfos_ = std::move(Cdb.methodInfos_);
s_methodInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
s_functionInfos_ = std::move(Cdb.functionInfos_);
s_functionInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
s_propertyInfos_ = std::move(Cdb.propertyInfos_);
s_propertyInfos_.push_back(NamedPropertyInfo{nullptr, nullptr});
s_variableInfos_ = std::move(Cdb.variableInfos_);
s_variableInfos_.push_back(NamedPropertyInfo{nullptr, nullptr});
pesapi_class_type_info(PUERTS_BINDING_PROTO_ID(), StaticTypeId<T>::get(), s_constructorInfos_.data(), s_methodInfos_.data(),
s_functionInfos_.data(), s_propertyInfos_.data(), s_variableInfos_.data());
}
template <typename T>
using Converter = Converter<T>;
template <typename T>
using CustomArgumentBufferType = CustomArgumentBufferType<T>;
};
class StringHolder
{
public:
StringHolder(pesapi_env env, pesapi_value value)
{
if (!value)
return;
if (pesapi_is_binary(env, value))
{
needFree_ = false;
size_t length = 0;
str_ = (char*) pesapi_get_value_binary(env, value, &length);
}
else
{
size_t length = 0;
str_ = (char*) pesapi_get_value_string_utf8(env, value, nullptr, &length);
needFree_ = false;
if (!str_)
{
str_ = new char[length + 1];
pesapi_get_value_string_utf8(env, value, str_, &length);
needFree_ = true;
}
}
}
// Disallow copying and assigning.
StringHolder(const StringHolder&) = delete;
void operator=(const StringHolder&) = delete;
~StringHolder()
{
if (needFree_ && str_)
{
delete[] str_;
}
}
const char* Data() const
{
return str_;
}
private:
char* str_;
bool needFree_;
};
template <>
struct CustomArgumentBufferType<const char*>
{
using type = StringHolder;
static constexpr bool enable = true;
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 8 && std::is_signed<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_int64(env, value);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_int64(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_int64(env, value);
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 8 && !std::is_signed<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_uint64(env, value);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_uint64(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_uint64(env, value);
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) < 8 && std::is_signed<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_int32(env, value);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_int32(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_int32(env, value);
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) < 8 && !std::is_signed<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_uint32(env, value);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_uint32(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_uint32(env, value);
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_int32(env, static_cast<int>(value));
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_int32(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_int32(env, value);
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_double(env, value);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_double(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_double(env, value);
}
};
template <>
struct Converter<std::string>
{
static pesapi_value toScript(pesapi_env env, std::string value)
{
return pesapi_create_string_utf8(env, value.c_str(), value.size());
}
static std::string toCpp(pesapi_env env, pesapi_value value)
{
size_t bufSize = 0;
const char* str = pesapi_get_value_string_utf8(env, value, nullptr, &bufSize);
if (str)
{
return std::string(str);
}
else
{
std::vector<char> buffer(bufSize + 1);
str = pesapi_get_value_string_utf8(env, value, buffer.data(), &bufSize);
return std::string(str);
}
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_string(env, value);
}
};
template <>
struct Converter<const char*>
{
static pesapi_value toScript(pesapi_env env, const char* value)
{
return pesapi_create_string_utf8(env, value, strlen(value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_string(env, value);
}
};
template <>
struct Converter<void*>
{
static pesapi_value toScript(pesapi_env env, void* value)
{
return pesapi_create_binary(env, value, 0);
}
static void* toCpp(pesapi_env env, pesapi_value value)
{
size_t bufsize;
return pesapi_get_value_binary(env, value, &bufsize);
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_binary(env, value);
}
};
template <>
struct Converter<bool>
{
static pesapi_value toScript(pesapi_env env, bool value)
{
return pesapi_create_boolean(env, value);
}
static bool toCpp(pesapi_env env, pesapi_value value)
{
return pesapi_get_value_bool(env, value);
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_boolean(env, value);
}
};
template <typename T>
struct Converter<std::reference_wrapper<T>, typename std::enable_if<!is_objecttype<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, const T& value)
{
return pesapi_boxing(env, Converter<T>::toScript(env, value));
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return Converter<T>::toCpp(env, pesapi_unboxing(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_boxed_value(env, value); // do not checked inner
}
};
template <typename T>
struct Converter<std::reference_wrapper<T>, typename std::enable_if<is_objecttype<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, const T& value)
{
return pesapi_boxing(env, Converter<T>::toScript(env, value));
}
static T* toCpp(pesapi_env env, pesapi_value value)
{
if (pesapi_is_object(env, value))
{
return Converter<T*>::toCpp(env, pesapi_unboxing(env, value));
}
return nullptr;
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_boxed_value(env, value); // do not checked inner
}
};
template <typename T>
struct Converter<T,
typename std::enable_if<is_script_type<typename std::remove_pointer<T>::type>::value && !std::is_array<T>::value &&
!std::is_const<typename std::remove_pointer<T>::type>::value && std::is_pointer<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_binary(env, value, 0);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
size_t bufsize;
return static_cast<T>(pesapi_get_value_binary(env, value, &bufsize));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_binary(env, value);
}
};
template <typename T, std::size_t Size>
struct Converter<T[Size], typename std::enable_if<is_script_type<T>::value && !std::is_const<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value[Size])
{
return pesapi_create_binary(env, value, sizeof(T) * Size);
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_binary(env, value);
}
};
template <class T>
struct Converter<T, typename std::enable_if<std::is_copy_constructible<T>::value && std::is_constructible<T>::value &&
is_objecttype<T>::value && !is_uetype<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_native_object_to_value(env, DynamicTypeId<T>::get(&value), new T(value), true);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
T* ptr = (static_cast<T*>(pesapi_get_native_object_ptr(env, value)));
return ptr ? *ptr : T{};
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_instance_of(env, StaticTypeId<T>::get(), value);
}
};
} // namespace pesapi_impl
} // namespace PUERTS_NAMESPACE