/* * 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 #include #include "pesapi.h" #include "TypeInfo.hpp" #define __DefObjectType_pesapi_impl(CLS) \ namespace PUERTS_NAMESPACE \ { \ template <> \ struct is_objecttype : public std::true_type \ { \ }; \ } #define __DefCDataPointerConverter_pesapi_impl(CLS) \ namespace PUERTS_NAMESPACE \ { \ namespace pesapi_impl \ { \ template <> \ struct Converter \ { \ static pesapi_value toScript(pesapi_env env, CLS* value) \ { \ return pesapi_native_object_to_value(env, DynamicTypeId::get(value), value, false); \ } \ static CLS* toCpp(pesapi_env env, pesapi_value value) \ { \ return static_cast(pesapi_get_native_object_ptr(env, value)); \ } \ static bool accept(pesapi_env env, pesapi_value value) \ { \ return pesapi_is_instance_of(env, StaticTypeId::get(), value); \ } \ }; \ } \ } #define __DefCDataConverter_pesapi_impl(CLS) \ namespace PUERTS_NAMESPACE \ { \ namespace pesapi_impl \ { \ template <> \ struct Converter \ { \ static pesapi_value toScript(pesapi_env env, CLS value) \ { \ return pesapi_native_object_to_value(env, DynamicTypeId::get(&value), new CLS(value), true); \ } \ static CLS toCpp(pesapi_env env, pesapi_value value) \ { \ return *static_cast(pesapi_get_native_object_ptr(env, value)); \ } \ static bool accept(pesapi_env env, pesapi_value value) \ { \ return pesapi_is_instance_of(env, StaticTypeId::get(), value); \ } \ }; \ } \ } namespace PUERTS_NAMESPACE { namespace pesapi_impl { template struct Converter; template 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 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 inline static T* FastGetNativeObjectPointer(pesapi_env env, pesapi_value value) { return static_cast(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 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::get(), Cdb.superTypeId_, Cdb.className_, reinterpret_cast(Cdb.constructor_), finalize, properties_count, properties, nullptr); static std::vector s_constructorInfos_{}; static std::vector s_methodInfos_{}; static std::vector s_functionInfos_{}; static std::vector s_propertyInfos_{}; static std::vector 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::get(), s_constructorInfos_.data(), s_methodInfos_.data(), s_functionInfos_.data(), s_propertyInfos_.data(), s_variableInfos_.data()); } template using Converter = Converter; template using CustomArgumentBufferType = CustomArgumentBufferType; }; 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 { using type = StringHolder; static constexpr bool enable = true; }; template struct Converter::value && sizeof(T) == 8 && std::is_signed::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(pesapi_get_value_int64(env, value)); } static bool accept(pesapi_env env, pesapi_value value) { return pesapi_is_int64(env, value); } }; template struct Converter::value && sizeof(T) == 8 && !std::is_signed::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(pesapi_get_value_uint64(env, value)); } static bool accept(pesapi_env env, pesapi_value value) { return pesapi_is_uint64(env, value); } }; template struct Converter::value && sizeof(T) < 8 && std::is_signed::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(pesapi_get_value_int32(env, value)); } static bool accept(pesapi_env env, pesapi_value value) { return pesapi_is_int32(env, value); } }; template struct Converter::value && sizeof(T) < 8 && !std::is_signed::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(pesapi_get_value_uint32(env, value)); } static bool accept(pesapi_env env, pesapi_value value) { return pesapi_is_uint32(env, value); } }; template struct Converter::value>::type> { static pesapi_value toScript(pesapi_env env, T value) { return pesapi_create_int32(env, static_cast(value)); } static T toCpp(pesapi_env env, pesapi_value value) { return static_cast(pesapi_get_value_int32(env, value)); } static bool accept(pesapi_env env, pesapi_value value) { return pesapi_is_int32(env, value); } }; template struct Converter::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(pesapi_get_value_double(env, value)); } static bool accept(pesapi_env env, pesapi_value value) { return pesapi_is_double(env, value); } }; template <> struct Converter { 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 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 { 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 { 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 { 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 struct Converter, typename std::enable_if::value>::type> { static pesapi_value toScript(pesapi_env env, const T& value) { return pesapi_boxing(env, Converter::toScript(env, value)); } static T toCpp(pesapi_env env, pesapi_value value) { return Converter::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 struct Converter, typename std::enable_if::value>::type> { static pesapi_value toScript(pesapi_env env, const T& value) { return pesapi_boxing(env, Converter::toScript(env, value)); } static T* toCpp(pesapi_env env, pesapi_value value) { if (pesapi_is_object(env, value)) { return Converter::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 struct Converter::type>::value && !std::is_array::value && !std::is_const::type>::value && std::is_pointer::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(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::value && !std::is_const::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 struct Converter::value && std::is_constructible::value && is_objecttype::value && !is_uetype::value>::type> { static pesapi_value toScript(pesapi_env env, T value) { return pesapi_native_object_to_value(env, DynamicTypeId::get(&value), new T(value), true); } static T toCpp(pesapi_env env, pesapi_value value) { T* ptr = (static_cast(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::get(), value); } }; } // namespace pesapi_impl } // namespace PUERTS_NAMESPACE