“初始化俯视角工程,带puerts,未编过”
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 "CoreMinimal.h"
|
||||
#include "ArrayBuffer.generated.h"
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FArrayBuffer
|
||||
{
|
||||
public:
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
public:
|
||||
void* Data;
|
||||
|
||||
size_t Length;
|
||||
|
||||
bool bCopy = false;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FArrayBufferValue
|
||||
{
|
||||
public:
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
public:
|
||||
TArray<uint8> Data;
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* 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 "PuertsNamespaceDef.h"
|
||||
#include "StaticCall.hpp"
|
||||
#include "ScriptBackend.hpp"
|
||||
#include "Object.hpp"
|
||||
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#if USING_IN_UNREAL_ENGINE
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Package.h"
|
||||
#include "UObject/Class.h"
|
||||
#else
|
||||
#include "JSClassRegister.h"
|
||||
#endif
|
||||
|
||||
#include "NamespaceDef.h"
|
||||
|
||||
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
|
||||
#pragma warning(push, 0)
|
||||
#include "v8.h"
|
||||
#pragma warning(pop)
|
||||
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
|
||||
|
||||
#if !defined(MAPPER_ISOLATE_DATA_POS)
|
||||
#define MAPPER_ISOLATE_DATA_POS 0
|
||||
#endif
|
||||
|
||||
#ifndef PESAPI_PRIVATE_DATA_POS_IN_ISOLATE
|
||||
#define PESAPI_PRIVATE_DATA_POS_IN_ISOLATE (MAPPER_ISOLATE_DATA_POS + 1)
|
||||
#endif
|
||||
|
||||
#define RELEASED_UOBJECT ((UObject*) 12)
|
||||
#define RELEASED_UOBJECT_MEMBER ((void*) 12)
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
template <typename T, typename FT, typename = void>
|
||||
struct TOuterLinker
|
||||
{
|
||||
V8_INLINE static void Link(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
V8_INLINE void LinkOuterImpl(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
|
||||
{
|
||||
#ifdef WITH_OUTER_LINK
|
||||
Inner.As<v8::Object>()->Set(Context, 0, Outer);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USING_IN_UNREAL_ENGINE
|
||||
FORCEINLINE UScriptStruct* GetScriptStructInCoreUObject(const TCHAR* Name)
|
||||
{
|
||||
static UPackage* CoreUObjectPkg = FindObjectChecked<UPackage>(nullptr, TEXT("/Script/CoreUObject"));
|
||||
return FindObjectChecked<UScriptStruct>(CoreUObjectPkg, Name);
|
||||
}
|
||||
|
||||
template <class T, typename Enable = void>
|
||||
struct TScriptStructTraits
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FVector>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return TBaseStructure<FVector>::Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FVector2D>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return TBaseStructure<FVector2D>::Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FVector4>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return TBaseStructure<FVector4>::Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FRotator>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return TBaseStructure<FRotator>::Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FQuat>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return TBaseStructure<FQuat>::Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FTransform>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return TBaseStructure<FTransform>::Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FLinearColor>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return TBaseStructure<FLinearColor>::Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FColor>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return TBaseStructure<FColor>::Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FGuid>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return TBaseStructure<FGuid>::Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FBox2D>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return TBaseStructure<FBox2D>::Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FIntPoint>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return GetScriptStructInCoreUObject(TEXT("IntPoint"));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FIntVector>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return GetScriptStructInCoreUObject(TEXT("IntVector"));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TScriptStructTraits<FPlane>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return GetScriptStructInCoreUObject(TEXT("Plane"));
|
||||
}
|
||||
};
|
||||
|
||||
template <class...>
|
||||
using ToVoid = void;
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct HasStaticStructHelper : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct HasStaticStructHelper<T, ToVoid<decltype(&T::StaticStruct)>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TScriptStructTraits<T, typename std::enable_if<HasStaticStructHelper<T>::value>::type>
|
||||
{
|
||||
static UScriptStruct* Get()
|
||||
{
|
||||
return T::StaticStruct();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename FT>
|
||||
struct TOuterLinker<T, FT, ToVoid<decltype(&TScriptStructTraits<FT>::Get)>>
|
||||
{
|
||||
V8_INLINE static void Link(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
|
||||
{
|
||||
LinkOuterImpl(Context, Outer, Inner);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class JSENV_API DataTransfer
|
||||
{
|
||||
public:
|
||||
FORCEINLINE static void* MakeAddressWithHighPartOfTwo(void* Address1, void* Address2)
|
||||
{
|
||||
UPTRINT High = reinterpret_cast<UPTRINT>(Address1) & (((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //清除低位
|
||||
UPTRINT Low = (reinterpret_cast<UPTRINT>(Address2) >> (sizeof(UPTRINT) / 2)) &
|
||||
~(((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //右移,然后清除高位
|
||||
return reinterpret_cast<void*>(High | Low);
|
||||
}
|
||||
|
||||
FORCEINLINE static void SplitAddressToHighPartOfTwo(const void* Address, UPTRINT& High, UPTRINT& Low)
|
||||
{
|
||||
High = reinterpret_cast<UPTRINT>(Address) & (((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //清除低位
|
||||
Low = reinterpret_cast<UPTRINT>(Address) << (sizeof(UPTRINT) / 2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCEINLINE static T* GetPointerFast(v8::Local<v8::Object> Object, int Index)
|
||||
{
|
||||
int P1 = Index << 1;
|
||||
int P2 = P1 + 1;
|
||||
if (V8_LIKELY(Object->InternalFieldCount() > P2))
|
||||
{
|
||||
return static_cast<T*>(MakeAddressWithHighPartOfTwo(
|
||||
Object->GetAlignedPointerFromInternalField(P1), Object->GetAlignedPointerFromInternalField(P2)));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCEINLINE static T* GetPointerFast(v8::Local<v8::Object> Object)
|
||||
{
|
||||
if (V8_LIKELY(Object->InternalFieldCount() > 1))
|
||||
{
|
||||
return static_cast<T*>(MakeAddressWithHighPartOfTwo(
|
||||
Object->GetAlignedPointerFromInternalField(0), Object->GetAlignedPointerFromInternalField(1)));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//替代 Object->SetAlignedPointerInInternalField(Index, Ptr);
|
||||
FORCEINLINE static void SetPointer(v8::Isolate* Isolate, v8::Local<v8::Object> Object, const void* Ptr, int Index)
|
||||
{
|
||||
// Object->SetInternalField(Index, v8::External::New(Isolate, Ptr));
|
||||
// Object->SetAlignedPointerInInternalField(Index, Ptr);
|
||||
UPTRINT High;
|
||||
UPTRINT Low;
|
||||
SplitAddressToHighPartOfTwo(Ptr, High, Low);
|
||||
Object->SetAlignedPointerInInternalField(Index * 2, reinterpret_cast<void*>(High));
|
||||
Object->SetAlignedPointerInInternalField(Index * 2 + 1, reinterpret_cast<void*>(Low));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCEINLINE static T* IsolateData(v8::Isolate* Isolate)
|
||||
{
|
||||
return static_cast<T*>(Isolate->GetData(MAPPER_ISOLATE_DATA_POS));
|
||||
}
|
||||
|
||||
FORCEINLINE static void* GetIsolatePrivateData(v8::Isolate* Isolate)
|
||||
{
|
||||
return Isolate->GetData(PESAPI_PRIVATE_DATA_POS_IN_ISOLATE);
|
||||
}
|
||||
|
||||
FORCEINLINE static void SetIsolatePrivateData(v8::Isolate* Isolate, void* PrivateData)
|
||||
{
|
||||
Isolate->SetData(PESAPI_PRIVATE_DATA_POS_IN_ISOLATE, PrivateData);
|
||||
}
|
||||
|
||||
static v8::Local<v8::Value> FindOrAddCData(
|
||||
v8::Isolate* Isolate, v8::Local<v8::Context> Context, const void* TypeId, const void* Ptr, bool PassByPointer);
|
||||
|
||||
static bool IsInstanceOf(v8::Isolate* Isolate, const void* TypeId, v8::Local<v8::Object> JsObject);
|
||||
|
||||
static v8::Local<v8::Value> UnRef(v8::Isolate* Isolate, const v8::Local<v8::Value>& Value);
|
||||
|
||||
static void UpdateRef(v8::Isolate* Isolate, v8::Local<v8::Value> Outer, const v8::Local<v8::Value>& Value);
|
||||
|
||||
static std::weak_ptr<int> GetJsEnvLifeCycleTracker(v8::Isolate* Isolate);
|
||||
|
||||
#if USING_IN_UNREAL_ENGINE
|
||||
template <typename T>
|
||||
static v8::Local<v8::Value> FindOrAddObject(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, T* UEObject)
|
||||
{
|
||||
return FindOrAddObject(Isolate, Context, UEObject == nullptr ? T::StaticClass() : UEObject->GetClass(), UEObject);
|
||||
}
|
||||
|
||||
static v8::Local<v8::Value> FindOrAddObject(
|
||||
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, UClass* Class, UObject* UEObject);
|
||||
|
||||
template <typename T>
|
||||
static v8::Local<v8::Value> FindOrAddStruct(v8::Isolate* Isolate, v8::Local<v8::Context> Context, void* Ptr, bool PassByPointer)
|
||||
{
|
||||
return FindOrAddStruct(Isolate, Context, TScriptStructTraits<T>::Get(), Ptr, PassByPointer);
|
||||
}
|
||||
|
||||
static v8::Local<v8::Value> FindOrAddStruct(
|
||||
v8::Isolate* Isolate, v8::Local<v8::Context> Context, UScriptStruct* ScriptStruct, void* Ptr, bool PassByPointer);
|
||||
|
||||
template <typename T>
|
||||
static bool IsInstanceOf(v8::Isolate* Isolate, v8::Local<v8::Object> JsObject)
|
||||
{
|
||||
return IsInstanceOf(Isolate, TScriptStructTraits<T>::Get(), JsObject);
|
||||
}
|
||||
|
||||
static bool IsInstanceOf(v8::Isolate* Isolate, UStruct* Struct, v8::Local<v8::Object> JsObject);
|
||||
|
||||
static FString ToFString(v8::Isolate* Isolate, v8::Local<v8::Value> Value);
|
||||
|
||||
static void ThrowException(v8::Isolate* Isolate, const char* Message);
|
||||
#endif
|
||||
|
||||
template <typename T1, typename T2>
|
||||
FORCEINLINE static void LinkOuter(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
|
||||
{
|
||||
TOuterLinker<T1, T2>::Link(Context, Outer, Inner);
|
||||
}
|
||||
|
||||
FORCEINLINE static v8::Local<v8::ArrayBuffer> NewArrayBuffer(v8::Local<v8::Context> Context, void* Data, size_t DataLength)
|
||||
{
|
||||
#if defined(HAS_ARRAYBUFFER_NEW_WITHOUT_STL)
|
||||
return v8::ArrayBuffer_New_Without_Stl(Context->GetIsolate(), Data, DataLength);
|
||||
#else
|
||||
#if USING_IN_UNREAL_ENGINE
|
||||
return v8::ArrayBuffer::New(Context->GetIsolate(), Data, DataLength);
|
||||
#else
|
||||
auto Backing = v8::ArrayBuffer::NewBackingStore(Data, DataLength, v8::BackingStore::EmptyDeleter, nullptr);
|
||||
return v8::ArrayBuffer::New(Context->GetIsolate(), std::move(Backing));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
FORCEINLINE static void* GetArrayBufferData(v8::Local<v8::ArrayBuffer> InArrayBuffer)
|
||||
{
|
||||
size_t DataLength;
|
||||
return GetArrayBufferData(InArrayBuffer, DataLength);
|
||||
}
|
||||
|
||||
FORCEINLINE static void* GetArrayBufferData(v8::Local<v8::ArrayBuffer> InArrayBuffer, size_t& DataLength)
|
||||
{
|
||||
#if defined(HAS_ARRAYBUFFER_NEW_WITHOUT_STL)
|
||||
return v8::ArrayBuffer_Get_Data(InArrayBuffer, DataLength);
|
||||
#else
|
||||
#if USING_IN_UNREAL_ENGINE
|
||||
DataLength = InArrayBuffer->GetContents().ByteLength();
|
||||
return InArrayBuffer->GetContents().Data();
|
||||
#else
|
||||
auto BS = InArrayBuffer->GetBackingStore();
|
||||
DataLength = BS->ByteLength();
|
||||
return BS->Data();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 "NamespaceDef.h"
|
||||
|
||||
#include "CoreUObject.h"
|
||||
|
||||
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
|
||||
#pragma warning(push, 0)
|
||||
#include "v8.h"
|
||||
#pragma warning(pop)
|
||||
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
|
||||
|
||||
class UDynamicDelegateProxy;
|
||||
class UJSGeneratedFunction;
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
class IDynamicInvoker
|
||||
{
|
||||
public:
|
||||
virtual void InvokeDelegateCallback(UDynamicDelegateProxy* Proxy, void* Params) = 0;
|
||||
|
||||
#if !defined(ENGINE_INDEPENDENT_JSENV)
|
||||
virtual void JsConstruct(UClass* Class, UObject* Object, const v8::UniquePersistent<v8::Function>& Constructor,
|
||||
const v8::UniquePersistent<v8::Object>& Prototype) = 0;
|
||||
|
||||
virtual void InvokeJsMethod(UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM) = 0;
|
||||
|
||||
virtual void InvokeMixinMethod(UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM) = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 "CoreMinimal.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "ExtensionMethods.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class JSENV_API UExtensionMethods : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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 "inttypes.h"
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
typedef void (*FuncPtr)();
|
||||
|
||||
JSENV_API void SetFunctionArray(FuncPtr* FuncArray, uint32_t FuncArrayLength);
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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 "functional"
|
||||
|
||||
#if USING_IN_UNREAL_ENGINE
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
|
||||
#pragma warning(push, 0)
|
||||
#include "v8.h"
|
||||
#pragma warning(pop)
|
||||
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
|
||||
#else
|
||||
#define JSENV_API
|
||||
#define FORCEINLINE V8_INLINE
|
||||
#define UPTRINT uintptr_t
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "PuertsNamespaceDef.h"
|
||||
|
||||
#include "pesapi.h"
|
||||
#include "TypeInfo.hpp"
|
||||
|
||||
#if USING_IN_UNREAL_ENGINE
|
||||
static const FAnsiStringView EditorOnlyPropertySuffix = "_EditorOnly";
|
||||
#endif
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
class CFunctionInfo;
|
||||
|
||||
MSVC_PRAGMA(warning(push))
|
||||
MSVC_PRAGMA(warning(disable : 4191))
|
||||
struct JSENV_API JSFunctionInfo
|
||||
{
|
||||
JSFunctionInfo() : Name(nullptr), Callback(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
JSFunctionInfo(
|
||||
const char* InName, pesapi_callback InCallback, void* InData = nullptr, const CFunctionInfo* InReflectionInfo = nullptr)
|
||||
: Name(InName), Callback(InCallback), Data(InData), ReflectionInfo(InReflectionInfo)
|
||||
{
|
||||
}
|
||||
|
||||
template <class CallbackType>
|
||||
JSFunctionInfo(
|
||||
const char* InName, CallbackType InCallback, void* InData = nullptr, const CFunctionInfo* InReflectionInfo = nullptr)
|
||||
: Name(InName), Callback(reinterpret_cast<pesapi_callback>(InCallback)), Data(InData), ReflectionInfo(InReflectionInfo)
|
||||
{
|
||||
}
|
||||
|
||||
const char* Name;
|
||||
pesapi_callback Callback;
|
||||
void* Data = nullptr;
|
||||
const CFunctionInfo* ReflectionInfo = nullptr;
|
||||
};
|
||||
|
||||
struct JSENV_API JSPropertyInfo
|
||||
{
|
||||
JSPropertyInfo() : Name(nullptr), Getter(nullptr), Setter(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
JSPropertyInfo(const char* InName, pesapi_callback InGetter, pesapi_callback InSetter, void* InGetterData = nullptr,
|
||||
void* InSetterData = nullptr)
|
||||
: Name(InName), Getter(InGetter), Setter(InSetter), GetterData(InGetterData), SetterData(InSetterData)
|
||||
{
|
||||
}
|
||||
|
||||
template <class CallbackType>
|
||||
JSPropertyInfo(const char* InName, CallbackType InGetter, CallbackType InSetter, void* InGetterData = nullptr,
|
||||
void* InSetterData = nullptr)
|
||||
: Name(InName)
|
||||
, Getter(reinterpret_cast<pesapi_callback>(InGetter))
|
||||
, Setter(reinterpret_cast<pesapi_callback>(InSetter))
|
||||
, GetterData(InGetterData)
|
||||
, SetterData(InSetterData)
|
||||
{
|
||||
}
|
||||
|
||||
const char* Name;
|
||||
pesapi_callback Getter;
|
||||
pesapi_callback Setter;
|
||||
void* GetterData = nullptr;
|
||||
void* SetterData = nullptr;
|
||||
};
|
||||
|
||||
struct NamedFunctionInfo;
|
||||
struct NamedPropertyInfo;
|
||||
|
||||
struct JSENV_API JSClassDefinition
|
||||
{
|
||||
const void* TypeId;
|
||||
const void* SuperTypeId;
|
||||
const char* ScriptName;
|
||||
const char* UETypeName;
|
||||
pesapi_constructor Initialize;
|
||||
template <class InitializeType>
|
||||
void SetInitialize(InitializeType InInitialize)
|
||||
{
|
||||
Initialize = reinterpret_cast<pesapi_constructor>(InInitialize);
|
||||
}
|
||||
JSFunctionInfo* Methods; //成员方法
|
||||
JSFunctionInfo* Functions; //静态方法
|
||||
JSPropertyInfo* Properties; //成员属性
|
||||
JSPropertyInfo* Variables; //静态属性
|
||||
pesapi_finalize Finalize;
|
||||
// int InternalFieldCount;
|
||||
NamedFunctionInfo* ConstructorInfos;
|
||||
NamedFunctionInfo* MethodInfos;
|
||||
NamedFunctionInfo* FunctionInfos;
|
||||
NamedPropertyInfo* PropertyInfos;
|
||||
NamedPropertyInfo* VariableInfos;
|
||||
void* Data = nullptr;
|
||||
pesapi_on_native_object_enter OnEnter = nullptr;
|
||||
pesapi_on_native_object_exit OnExit = nullptr;
|
||||
};
|
||||
MSVC_PRAGMA(warning(pop))
|
||||
|
||||
#define JSClassEmptyDefinition \
|
||||
{ \
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \
|
||||
}
|
||||
|
||||
void JSENV_API RegisterJSClass(const JSClassDefinition& ClassDefinition);
|
||||
|
||||
void JSENV_API SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, const NamedFunctionInfo* MethodInfos,
|
||||
const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos, const NamedPropertyInfo* VariableInfos);
|
||||
|
||||
void JSENV_API ForeachRegisterClass(std::function<void(const JSClassDefinition* ClassDefinition)>);
|
||||
|
||||
JSENV_API const JSClassDefinition* FindClassByID(const void* TypeId);
|
||||
|
||||
JSENV_API void OnClassNotFound(pesapi_class_not_found_callback Callback);
|
||||
|
||||
JSENV_API const JSClassDefinition* LoadClassByID(const void* TypeId);
|
||||
|
||||
JSENV_API const JSClassDefinition* FindCppTypeClassByName(const std::string& Name);
|
||||
|
||||
JSENV_API bool TraceObjectLifecycle(const void* TypeId, pesapi_on_native_object_enter OnEnter, pesapi_on_native_object_exit OnExit);
|
||||
|
||||
#if USING_IN_UNREAL_ENGINE
|
||||
typedef void (*AddonRegisterFunc)(v8::Local<v8::Context> Context, v8::Local<v8::Object> Exports);
|
||||
|
||||
AddonRegisterFunc FindAddonRegisterFunc(const std::string& Name);
|
||||
|
||||
void RegisterAddon(const char* Name, AddonRegisterFunc RegisterFunc);
|
||||
|
||||
JSENV_API const JSClassDefinition* FindClassByType(UStruct* Type);
|
||||
|
||||
JSENV_API bool IsEditorOnlyUFunction(const UFunction* Func);
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
|
||||
#define PUERTS_MODULE(Name, RegFunc) \
|
||||
static struct FAutoRegisterFor##Name \
|
||||
{ \
|
||||
FAutoRegisterFor##Name() \
|
||||
{ \
|
||||
PUERTS_NAMESPACE::RegisterAddon(#Name, (RegFunc)); \
|
||||
} \
|
||||
} _AutoRegisterFor##Name
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 "PuertsNamespaceDef.h"
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
JSENV_API DECLARE_LOG_CATEGORY_EXTERN(Puerts, Log, All);
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
class JSENV_API ILogger
|
||||
{
|
||||
public:
|
||||
virtual void Log(const FString& Message) const = 0;
|
||||
virtual void Info(const FString& Message) const = 0;
|
||||
virtual void Warn(const FString& Message) const = 0;
|
||||
virtual void Error(const FString& Message) const = 0;
|
||||
};
|
||||
|
||||
class JSENV_API FDefaultLogger : public ILogger
|
||||
{
|
||||
public:
|
||||
virtual ~FDefaultLogger()
|
||||
{
|
||||
}
|
||||
void Log(const FString& Message) const override;
|
||||
void Info(const FString& Message) const override;
|
||||
void Warn(const FString& Message) const override;
|
||||
void Error(const FString& Message) const override;
|
||||
};
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 "PuertsNamespaceDef.h"
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
class IJSModuleLoader
|
||||
{
|
||||
public:
|
||||
virtual bool Search(const FString& RequiredDir, const FString& RequiredModule, FString& Path, FString& AbsolutePath) = 0;
|
||||
|
||||
virtual bool Load(const FString& Path, TArray<uint8>& Content) = 0;
|
||||
|
||||
virtual FString& GetScriptRoot() = 0;
|
||||
|
||||
virtual ~IJSModuleLoader()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class JSENV_API DefaultJSModuleLoader : public IJSModuleLoader
|
||||
{
|
||||
public:
|
||||
explicit DefaultJSModuleLoader(const FString& InScriptRoot) : ScriptRoot(InScriptRoot)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Search(const FString& RequiredDir, const FString& RequiredModule, FString& Path, FString& AbsolutePath) override;
|
||||
|
||||
virtual bool Load(const FString& Path, TArray<uint8>& Content) override;
|
||||
|
||||
virtual FString& GetScriptRoot() override;
|
||||
|
||||
virtual bool CheckExists(const FString& PathIn, FString& Path, FString& AbsolutePath);
|
||||
|
||||
virtual bool SearchModuleInDir(const FString& Dir, const FString& RequiredModule, FString& Path, FString& AbsolutePath);
|
||||
|
||||
virtual bool SearchModuleWithExtInDir(const FString& Dir, const FString& RequiredModule, FString& Path, FString& AbsolutePath);
|
||||
|
||||
FString ScriptRoot;
|
||||
};
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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 <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "JSLogger.h"
|
||||
#include "JSModuleLoader.h"
|
||||
#if !defined(ENGINE_INDEPENDENT_JSENV)
|
||||
#include "ExtensionMethods.h"
|
||||
#endif
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
class JSENV_API IJsEnv
|
||||
{
|
||||
public:
|
||||
virtual void Start(const FString& ModuleName, const TArray<TPair<FString, UObject*>>& Arguments) = 0;
|
||||
|
||||
virtual bool IdleNotificationDeadline(double DeadlineInSeconds) = 0;
|
||||
|
||||
virtual void LowMemoryNotification() = 0;
|
||||
|
||||
virtual void RequestMinorGarbageCollectionForTesting() = 0;
|
||||
|
||||
virtual void RequestFullGarbageCollectionForTesting() = 0;
|
||||
|
||||
virtual void WaitDebugger(double Timeout) = 0;
|
||||
|
||||
#if !defined(ENGINE_INDEPENDENT_JSENV)
|
||||
virtual void TryBindJs(const class UObjectBase* InObject) = 0;
|
||||
|
||||
virtual void RebindJs() = 0;
|
||||
#endif
|
||||
|
||||
virtual void ReloadModule(FName ModuleName, const FString& JsSource) = 0;
|
||||
|
||||
virtual void ReloadSource(const FString& Path, const std::string& JsSource) = 0;
|
||||
|
||||
virtual void OnSourceLoaded(std::function<void(const FString&)> Callback) = 0;
|
||||
|
||||
virtual FString CurrentStackTrace() = 0;
|
||||
|
||||
virtual void InitExtensionMethodsMap() = 0;
|
||||
|
||||
virtual ~IJsEnv()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class JSENV_API FJsEnv // : public TSharedFromThis<FJsEnv> // only a wrapper
|
||||
{
|
||||
public:
|
||||
explicit FJsEnv(const FString& ScriptRoot = TEXT("JavaScript"));
|
||||
|
||||
FJsEnv(std::shared_ptr<IJSModuleLoader> InModuleLoader, std::shared_ptr<ILogger> InLogger, int InDebugPort,
|
||||
std::function<void(const FString&)> InOnSourceLoadedCallback = nullptr, const FString InFlags = FString(),
|
||||
void* InExternalRuntime = nullptr, void* InExternalContext = nullptr);
|
||||
|
||||
void Start(const FString& ModuleName, const TArray<TPair<FString, UObject*>>& Arguments = TArray<TPair<FString, UObject*>>());
|
||||
|
||||
bool IdleNotificationDeadline(double DeadlineInSeconds);
|
||||
|
||||
void LowMemoryNotification();
|
||||
|
||||
// equivalent to Isolate->RequestGarbageCollectionForTesting(v8::Isolate::kMinorGarbageCollection)
|
||||
// It is only valid to call this function if --expose_gc was specified
|
||||
void RequestMinorGarbageCollectionForTesting();
|
||||
|
||||
// equivalent to Isolate->RequestGarbageCollectionForTesting(v8::Isolate::kFullGarbageCollection)
|
||||
void RequestFullGarbageCollectionForTesting();
|
||||
|
||||
void WaitDebugger(double Timeout = 0);
|
||||
|
||||
void TryBindJs(const class UObjectBase* InObject);
|
||||
|
||||
void ReloadModule(FName ModuleName, const FString& JsSource);
|
||||
|
||||
void ReloadSource(const FString& Path, const std::string& JsSource);
|
||||
|
||||
void OnSourceLoaded(std::function<void(const FString&)> Callback);
|
||||
|
||||
void RebindJs();
|
||||
|
||||
FString CurrentStackTrace();
|
||||
|
||||
void InitExtensionMethodsMap();
|
||||
|
||||
private:
|
||||
std::unique_ptr<IJsEnv> GameScript;
|
||||
};
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 <vector>
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "JsEnv.h"
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
class JSENV_API FJsEnvGroup
|
||||
{
|
||||
public:
|
||||
explicit FJsEnvGroup(int Size, const FString& ScriptRoot = TEXT("JavaScript"));
|
||||
|
||||
FJsEnvGroup(int Size, std::shared_ptr<IJSModuleLoader> InModuleLoader, std::shared_ptr<ILogger> InLogger, int InDebugStartPort,
|
||||
std::function<void(const FString&)> InOnSourceLoadedCallback = nullptr, const FString InFlags = FString(),
|
||||
void* InExternalRuntime = nullptr, void* InExternalContext = nullptr);
|
||||
|
||||
~FJsEnvGroup();
|
||||
|
||||
void TryBindJs(const class UObjectBase* InObject);
|
||||
|
||||
void ReloadModule(FName ModuleName, const FString& JsSource);
|
||||
|
||||
void RebindJs();
|
||||
|
||||
void InitExtensionMethodsMap();
|
||||
|
||||
std::shared_ptr<IJsEnv> Get(int Index);
|
||||
|
||||
void SetJsEnvSelector(std::function<int(UObject*, int)> InSelector);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<IJsEnv>> JsEnvList;
|
||||
|
||||
void Init();
|
||||
};
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 "CoreMinimal.h"
|
||||
#include "Modules/ModuleInterface.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
#if !defined(ENGINE_INDEPENDENT_JSENV)
|
||||
#include "EngineMinimal.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The public interface to this module
|
||||
*/
|
||||
class IJsEnvModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Singleton-like access to this module's interface. This is just for convenience!
|
||||
* Beware of calling this during the shutdown phase, though. Your module might have been unloaded already.
|
||||
*
|
||||
* @return Returns singleton instance, loading the module on demand if needed
|
||||
*/
|
||||
static inline IJsEnvModule& Get()
|
||||
{
|
||||
return FModuleManager::LoadModuleChecked<IJsEnvModule>("JsEnv");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true.
|
||||
*
|
||||
* @return True if the module is loaded and ready to use
|
||||
*/
|
||||
static inline bool IsAvailable()
|
||||
{
|
||||
return FModuleManager::Get().IsModuleLoaded("JsEnv");
|
||||
}
|
||||
|
||||
virtual void* GetV8Platform() = 0;
|
||||
};
|
||||
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* 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 "NamespaceDef.h"
|
||||
|
||||
#include "Binding.hpp"
|
||||
#include "JSLogger.h"
|
||||
#include "V8Utils.h"
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
class FJsObjectPropertyTranslator;
|
||||
}
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "JsObject.generated.h"
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FJsObject
|
||||
{
|
||||
public:
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
FJsObject() : Isolate(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
FJsObject(const FJsObject& InOther)
|
||||
{
|
||||
if (InOther.JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
JsEnvLifeCycleTracker = InOther.JsEnvLifeCycleTracker;
|
||||
if (!JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
GObject.Reset();
|
||||
GContext.Reset();
|
||||
Isolate = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Isolate = InOther.Isolate;
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
GContext.Reset(Isolate, InOther.GContext.Get(Isolate));
|
||||
GObject.Reset(Isolate, InOther.GObject.Get(Isolate));
|
||||
JsEnvLifeCycleTracker = PUERTS_NAMESPACE::DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
|
||||
}
|
||||
|
||||
FJsObject(v8::Local<v8::Context> InContext, v8::Local<v8::Object> InObject)
|
||||
: Isolate(InContext->GetIsolate()), GContext(InContext->GetIsolate(), InContext), GObject(InContext->GetIsolate(), InObject)
|
||||
{
|
||||
JsEnvLifeCycleTracker = PUERTS_NAMESPACE::DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
|
||||
}
|
||||
|
||||
~FJsObject()
|
||||
{
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
if (JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
#if V8_MAJOR_VERSION < 11
|
||||
GObject.Empty();
|
||||
GContext.Empty();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
GObject.Reset();
|
||||
GContext.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
FJsObject& operator=(const FJsObject& InOther)
|
||||
{
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
if (InOther.JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
JsEnvLifeCycleTracker = InOther.JsEnvLifeCycleTracker;
|
||||
if (!JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
GObject.Reset();
|
||||
GContext.Reset();
|
||||
Isolate = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
Isolate = InOther.Isolate;
|
||||
GContext.Reset(Isolate, InOther.GContext.Get(Isolate));
|
||||
GObject.Reset(Isolate, InOther.GObject.Get(Isolate));
|
||||
JsEnvLifeCycleTracker = PUERTS_NAMESPACE::DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Get(const char* Key) const
|
||||
{
|
||||
if (JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
UE_LOG(Puerts, Error, TEXT("JsEnv associated had release!"));
|
||||
return {};
|
||||
}
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
auto Context = GContext.Get(Isolate);
|
||||
v8::Context::Scope ContextScope(Context);
|
||||
auto Object = GObject.Get(Isolate);
|
||||
|
||||
auto MaybeValue = Object->Get(Context, PUERTS_NAMESPACE::v8_impl::Converter<const char*>::toScript(Context, Key));
|
||||
v8::Local<v8::Value> Val;
|
||||
if (MaybeValue.ToLocal(&Val))
|
||||
{
|
||||
return PUERTS_NAMESPACE::v8_impl::Converter<T>::toCpp(Context, Val);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Set(const char* Key, T Val) const
|
||||
{
|
||||
if (JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
UE_LOG(Puerts, Error, TEXT("JsEnv associated had release!"));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
auto Context = GContext.Get(Isolate);
|
||||
v8::Context::Scope ContextScope(Context);
|
||||
auto Object = GObject.Get(Isolate);
|
||||
|
||||
auto _UnUsed = Object->Set(Context, PUERTS_NAMESPACE::v8_impl::Converter<const char*>::toScript(Context, Key),
|
||||
PUERTS_NAMESPACE::v8_impl::Converter<T>::toScript(Context, Val));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void Action(Args... cppArgs) const
|
||||
{
|
||||
if (JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
UE_LOG(Puerts, Error, TEXT("JsEnv associated had release!"));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
auto Context = GContext.Get(Isolate);
|
||||
v8::Context::Scope ContextScope(Context);
|
||||
|
||||
auto Object = GObject.Get(Isolate);
|
||||
|
||||
if (!Object->IsFunction())
|
||||
{
|
||||
UE_LOG(Puerts, Error, TEXT("call a non-function object!"));
|
||||
return;
|
||||
}
|
||||
|
||||
v8::TryCatch TryCatch(Isolate);
|
||||
|
||||
auto _UnUsed = InvokeHelper(Context, Object, cppArgs...);
|
||||
|
||||
if (TryCatch.HasCaught())
|
||||
{
|
||||
UE_LOG(
|
||||
Puerts, Error, TEXT("call function throw: %s"), *PUERTS_NAMESPACE::FV8Utils::TryCatchToString(Isolate, &TryCatch));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Ret, typename... Args>
|
||||
Ret Func(Args... cppArgs) const
|
||||
{
|
||||
if (JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
UE_LOG(Puerts, Error, TEXT("JsEnv associated had release!"));
|
||||
return {};
|
||||
}
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
auto Context = GContext.Get(Isolate);
|
||||
v8::Context::Scope ContextScope(Context);
|
||||
|
||||
auto Object = GObject.Get(Isolate);
|
||||
|
||||
if (!Object->IsFunction())
|
||||
{
|
||||
UE_LOG(Puerts, Error, TEXT("call a non-function object!"));
|
||||
return {};
|
||||
}
|
||||
|
||||
v8::TryCatch TryCatch(Isolate);
|
||||
|
||||
auto MaybeRet = InvokeHelper(Context, Object, cppArgs...);
|
||||
|
||||
if (TryCatch.HasCaught())
|
||||
{
|
||||
UE_LOG(
|
||||
Puerts, Error, TEXT("call function throw: %s"), *PUERTS_NAMESPACE::FV8Utils::TryCatchToString(Isolate, &TryCatch));
|
||||
}
|
||||
|
||||
if (!MaybeRet.IsEmpty())
|
||||
{
|
||||
return PUERTS_NAMESPACE::v8_impl::Converter<Ret>::toCpp(Context, MaybeRet.ToLocalChecked());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
FORCEINLINE v8::Local<v8::Object> GetJsObject() const
|
||||
{
|
||||
if (JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
UE_LOG(Puerts, Error, TEXT("JsEnv associated had release!"));
|
||||
return {};
|
||||
}
|
||||
if (!GObject.IsEmpty())
|
||||
{
|
||||
return GObject.Get(Isolate);
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
FORCEINLINE auto InvokeHelper(v8::Local<v8::Context>& Context, v8::Local<v8::Object>& Object, Args... CppArgs) const
|
||||
{
|
||||
v8::Local<v8::Value> Argv[sizeof...(Args)]{PUERTS_NAMESPACE::v8_impl::Converter<Args>::toScript(Context, CppArgs)...};
|
||||
return Object.As<v8::Function>()->Call(Context, v8::Undefined(Isolate), sizeof...(Args), Argv);
|
||||
}
|
||||
|
||||
FORCEINLINE auto InvokeHelper(v8::Local<v8::Context>& Context, v8::Local<v8::Object>& Object) const
|
||||
{
|
||||
return Object.As<v8::Function>()->Call(Context, v8::Undefined(Isolate), 0, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Isolate* Isolate;
|
||||
#if V8_MAJOR_VERSION >= 11
|
||||
v8::Persistent<v8::Context> GContext;
|
||||
v8::Persistent<v8::Object> GObject;
|
||||
#else
|
||||
v8::Global<v8::Context> GContext;
|
||||
v8::Global<v8::Object> GObject;
|
||||
#endif
|
||||
std::weak_ptr<int> JsEnvLifeCycleTracker;
|
||||
|
||||
friend struct PUERTS_NAMESPACE::v8_impl::Converter<FJsObject>;
|
||||
friend class PUERTS_NAMESPACE::FJsObjectPropertyTranslator;
|
||||
};
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
template <>
|
||||
struct ScriptTypeName<FJsObject>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("object");
|
||||
}
|
||||
};
|
||||
|
||||
namespace v8_impl
|
||||
{
|
||||
template <>
|
||||
struct Converter<FJsObject>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FJsObject value)
|
||||
{
|
||||
return value.GObject.Get(context->GetIsolate());
|
||||
}
|
||||
|
||||
static FJsObject toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return FJsObject(context, value.As<v8::Object>());
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsObject();
|
||||
}
|
||||
};
|
||||
} // namespace v8_impl
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* 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 "PuertsNamespaceDef.h"
|
||||
|
||||
#if defined(WITH_QJS_NAMESPACE_SUFFIX)
|
||||
namespace v8 = v8_qjs;
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#if defined(BUILDING_PES_EXTENSION)
|
||||
#include "PesapiObject.hpp"
|
||||
#endif
|
||||
#if !defined(BUILDING_PES_EXTENSION) || defined(PES_EXTENSION_WITH_V8_API)
|
||||
#include "V8Object.hpp"
|
||||
#endif
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
constexpr std::size_t NumDigits(std::size_t n)
|
||||
{
|
||||
return n < 10 ? 1 : NumDigits(n / 10) + 1;
|
||||
}
|
||||
|
||||
template <char... Chars>
|
||||
struct CharList
|
||||
{
|
||||
const char Str[sizeof...(Chars)] = {Chars...};
|
||||
};
|
||||
|
||||
template <std::size_t D, std::size_t N, char... Chars>
|
||||
struct SI2A
|
||||
{
|
||||
using type = typename SI2A<D - 1, N / 10, '0' + N % 10, Chars...>::type;
|
||||
};
|
||||
|
||||
template <std::size_t N, char... Chars>
|
||||
struct SI2A<1, N, Chars...>
|
||||
{
|
||||
using type = CharList<'0' + N, Chars..., '\0'>;
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
using SI2A_T = typename SI2A<NumDigits(N), N>::type;
|
||||
|
||||
template <size_t N, typename... Rest>
|
||||
struct ParamsDecl
|
||||
{
|
||||
};
|
||||
|
||||
template <size_t N, typename T, typename... Rest>
|
||||
struct ParamsDecl<N, T, Rest...>
|
||||
{
|
||||
static constexpr auto Get()
|
||||
{
|
||||
return ParamsDecl<N, T>::Get() + Literal(", ") + ParamsDecl<N + 1, Rest...>::Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N, typename T>
|
||||
struct ParamsDecl<N, T>
|
||||
{
|
||||
static constexpr auto Get()
|
||||
{
|
||||
return Literal("p") + Literal(SI2A_T<N>().Str) + Literal(":") + ScriptTypeNameWithNamespace<T>::value();
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
struct ParamsDecl<N>
|
||||
{
|
||||
static constexpr auto Get()
|
||||
{
|
||||
return Literal("");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct ScriptTypeName<std::function<R(Args...)>>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("(") + internal::ParamsDecl<0, Args...>::Get() + internal::Literal(") => ") +
|
||||
ScriptTypeNameWithNamespace<R>::value();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 "CoreMinimal.h"
|
||||
#include "UObject/GCObject.h"
|
||||
#include "PuertsNamespaceDef.h"
|
||||
|
||||
#ifdef THREAD_SAFE
|
||||
#if defined(WITH_QJS_NAMESPACE_SUFFIX)
|
||||
namespace v8_qjs
|
||||
#else
|
||||
namespace v8
|
||||
#endif
|
||||
{
|
||||
class Isolate;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
class JSENV_API FObjectRetainer : public FGCObject
|
||||
{
|
||||
public:
|
||||
void Retain(UObject* Object);
|
||||
|
||||
void Release(UObject* Object);
|
||||
|
||||
void Clear();
|
||||
|
||||
virtual void AddReferencedObjects(FReferenceCollector& Collector) override;
|
||||
|
||||
virtual ~FObjectRetainer() override;
|
||||
|
||||
FORCEINLINE void SetName(FString InName)
|
||||
{
|
||||
Name = InName;
|
||||
}
|
||||
|
||||
virtual FString GetReferencerName() const override;
|
||||
|
||||
#ifdef THREAD_SAFE
|
||||
FCriticalSection RetainedObjectsCritical;
|
||||
#endif
|
||||
|
||||
private:
|
||||
TSet<UObject*> RetainedObjects;
|
||||
|
||||
FString Name = TEXT("FObjectRetainer");
|
||||
};
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 "PuertsNamespaceDef.h"
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
FORCEINLINE FString FilenameToTypeScriptVariableName(const FString& Filename)
|
||||
{
|
||||
FString TypeScriptVariable;
|
||||
if (FChar::IsDigit(Filename[0]))
|
||||
{
|
||||
TypeScriptVariable.AppendChar('_');
|
||||
}
|
||||
for (TCHAR c : Filename)
|
||||
{
|
||||
if (FChar::IsAlnum(c) || c == '_' || c == '$' || FChar::IsAlpha(c))
|
||||
{
|
||||
if (c == '$')
|
||||
{
|
||||
TypeScriptVariable.AppendChar('$');
|
||||
}
|
||||
TypeScriptVariable.AppendChar(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
TypeScriptVariable.AppendChar('$');
|
||||
TypeScriptVariable.Append(FString::Printf(TEXT("%d"), (int) c));
|
||||
TypeScriptVariable.AppendChar('$');
|
||||
}
|
||||
}
|
||||
return TypeScriptVariable;
|
||||
}
|
||||
|
||||
FORCEINLINE FString TypeScriptVariableNameToFilename(const FString& TypeScriptVariable)
|
||||
{
|
||||
FString Filename;
|
||||
int32 i = 0;
|
||||
if (TypeScriptVariable.StartsWith("_") && TypeScriptVariable.Len() > 1 && FChar::IsDigit(TypeScriptVariable[1]))
|
||||
{
|
||||
i = 1;
|
||||
}
|
||||
while (i < TypeScriptVariable.Len())
|
||||
{
|
||||
if (TypeScriptVariable[i] != '$')
|
||||
{
|
||||
Filename.AppendChar(TypeScriptVariable[i]);
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i + 1 < TypeScriptVariable.Len() && TypeScriptVariable[i + 1] == '$')
|
||||
{
|
||||
Filename.AppendChar('$');
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
FString ascii_str;
|
||||
++i;
|
||||
while (i < TypeScriptVariable.Len() && FChar::IsDigit(TypeScriptVariable[i]))
|
||||
{
|
||||
ascii_str.AppendChar(TypeScriptVariable[i]);
|
||||
++i;
|
||||
}
|
||||
if (i < TypeScriptVariable.Len() && TypeScriptVariable[i] == '$')
|
||||
{
|
||||
++i;
|
||||
}
|
||||
TCHAR original_char = static_cast<TCHAR>(FCString::Atoi(*ascii_str));
|
||||
Filename.AppendChar(original_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Filename;
|
||||
}
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* 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 "Binding.hpp"
|
||||
#include "pesapi.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
class AutoValueScope
|
||||
{
|
||||
public:
|
||||
AutoValueScope(pesapi_env_ref env_holder)
|
||||
{
|
||||
scope = pesapi_open_scope(env_holder);
|
||||
}
|
||||
|
||||
~AutoValueScope()
|
||||
{
|
||||
pesapi_close_scope(scope);
|
||||
}
|
||||
|
||||
pesapi_scope scope;
|
||||
};
|
||||
} // namespace internal
|
||||
namespace pesapi_impl
|
||||
{
|
||||
static inline void REPORT_EXCEPTION(const char* MSG)
|
||||
{
|
||||
std::cout << "call function throw: " << MSG << std::endl;
|
||||
}
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
Object(pesapi_env env, pesapi_value value)
|
||||
{
|
||||
if (!env || !value || IsNullOrUndefined(env, value))
|
||||
{
|
||||
env_holder = nullptr;
|
||||
value_holder = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
env_holder = pesapi_create_env_ref(env);
|
||||
value_holder = pesapi_create_value_ref(env, value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Object(const Object& InOther)
|
||||
{
|
||||
if (!InOther.env_holder || !InOther.value_holder)
|
||||
{
|
||||
env_holder = nullptr;
|
||||
value_holder = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
env_holder = pesapi_duplicate_env_ref(InOther.env_holder);
|
||||
value_holder = pesapi_duplicate_value_ref(InOther.value_holder);
|
||||
}
|
||||
}
|
||||
|
||||
~Object()
|
||||
{
|
||||
if (!env_holder || !value_holder)
|
||||
return;
|
||||
pesapi_release_value_ref(value_holder);
|
||||
pesapi_release_env_ref(env_holder);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Get(const char* key) const
|
||||
{
|
||||
if (!env_holder || !value_holder)
|
||||
return {};
|
||||
internal::AutoValueScope ValueScope(env_holder);
|
||||
auto env = pesapi_get_env_from_ref(env_holder);
|
||||
auto object = pesapi_get_value_from_ref(env, value_holder);
|
||||
|
||||
auto value = pesapi_get_property(env, object, key);
|
||||
if (!pesapi_is_undefined(env, value))
|
||||
{
|
||||
return pesapi_impl::Converter<T>::toCpp(env, value);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Set(const char* key, T val) const
|
||||
{
|
||||
if (!env_holder || !value_holder)
|
||||
return;
|
||||
internal::AutoValueScope ValueScope(env_holder);
|
||||
auto env = pesapi_get_env_from_ref(env_holder);
|
||||
auto object = pesapi_get_value_from_ref(env, value_holder);
|
||||
|
||||
pesapi_set_property(env, object, key, pesapi_impl::Converter<T>::toScript(env, val));
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
if (!env_holder || !value_holder)
|
||||
return false;
|
||||
internal::AutoValueScope ValueScope(env_holder);
|
||||
auto env = pesapi_get_env_from_ref(env_holder);
|
||||
auto val = pesapi_get_value_from_ref(env, value_holder);
|
||||
return val && pesapi_is_object(env, val);
|
||||
}
|
||||
|
||||
void operator=(const Object& obj)
|
||||
{
|
||||
env_holder = pesapi_duplicate_env_ref(obj.env_holder);
|
||||
value_holder = pesapi_duplicate_value_ref(obj.value_holder);
|
||||
}
|
||||
|
||||
pesapi_env_ref env_holder;
|
||||
pesapi_value_ref value_holder;
|
||||
|
||||
friend struct pesapi_impl::Converter<Object>;
|
||||
};
|
||||
|
||||
class Function : public Object
|
||||
{
|
||||
public:
|
||||
Function(pesapi_env env, pesapi_value value) : Object(env, value)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void Action(Args... cppArgs) const
|
||||
{
|
||||
if (!env_holder || !value_holder)
|
||||
return;
|
||||
internal::AutoValueScope ValueScope(env_holder);
|
||||
auto env = pesapi_get_env_from_ref(env_holder);
|
||||
auto object = pesapi_get_value_from_ref(env, value_holder);
|
||||
|
||||
auto _un_used = invokeHelper(env, object, cppArgs...);
|
||||
|
||||
if (pesapi_has_caught(ValueScope.scope))
|
||||
{
|
||||
REPORT_EXCEPTION(pesapi_get_exception_as_string(ValueScope.scope, true));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Ret, typename... Args>
|
||||
Ret Func(Args... cppArgs) const
|
||||
{
|
||||
if (!env_holder || !value_holder)
|
||||
return {};
|
||||
internal::AutoValueScope ValueScope(env_holder);
|
||||
auto env = pesapi_get_env_from_ref(env_holder);
|
||||
auto object = pesapi_get_value_from_ref(env, value_holder);
|
||||
|
||||
auto ret = invokeHelper(env, object, cppArgs...);
|
||||
|
||||
if (pesapi_has_caught(ValueScope.scope))
|
||||
{
|
||||
REPORT_EXCEPTION(pesapi_get_exception_as_string(ValueScope.scope, true));
|
||||
return {};
|
||||
}
|
||||
else
|
||||
{
|
||||
return pesapi_impl::Converter<Ret>::toCpp(env, ret);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
if (!env_holder || !value_holder)
|
||||
return false;
|
||||
internal::AutoValueScope ValueScope(env_holder);
|
||||
auto env = pesapi_get_env_from_ref(env_holder);
|
||||
auto val = pesapi_get_value_from_ref(env, value_holder);
|
||||
return val && pesapi_is_function(env, val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void SetWeakAndOwnBy(const T* Owner)
|
||||
{
|
||||
internal::AutoValueScope ValueScope(env_holder);
|
||||
auto env = pesapi_get_env_from_ref(env_holder);
|
||||
|
||||
auto owner = pesapi_native_object_to_value(env, StaticTypeId<T>::get(), Owner, false);
|
||||
auto val = pesapi_get_value_from_ref(env, value_holder);
|
||||
if (pesapi_set_owner(env, val, owner))
|
||||
{
|
||||
pesapi_set_ref_weak(env, value_holder);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename... Args>
|
||||
auto invokeHelper(pesapi_env env, pesapi_value func, Args... CppArgs) const
|
||||
{
|
||||
pesapi_value argv[sizeof...(Args)]{pesapi_impl::Converter<Args>::toScript(env, CppArgs)...};
|
||||
return pesapi_call_function(env, func, nullptr, sizeof...(Args), argv);
|
||||
}
|
||||
|
||||
auto invokeHelper(pesapi_env env, pesapi_value func) const
|
||||
{
|
||||
return pesapi_call_function(env, func, nullptr, 0, nullptr);
|
||||
}
|
||||
|
||||
friend struct pesapi_impl::Converter<Function>;
|
||||
};
|
||||
|
||||
} // namespace pesapi_impl
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<pesapi_impl::Object>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("object");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<pesapi_impl::Function>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("Function");
|
||||
}
|
||||
};
|
||||
|
||||
namespace pesapi_impl
|
||||
{
|
||||
template <>
|
||||
struct Converter<Object>
|
||||
{
|
||||
static pesapi_value toScript(pesapi_env env, Object value)
|
||||
{
|
||||
return pesapi_get_value_from_ref(env, value.value_holder);
|
||||
}
|
||||
|
||||
static Object toCpp(pesapi_env env, pesapi_value value)
|
||||
{
|
||||
return Object(env, value);
|
||||
}
|
||||
|
||||
static bool accept(pesapi_env env, pesapi_value value)
|
||||
{
|
||||
return pesapi_is_object(env, value);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<Function>
|
||||
{
|
||||
static pesapi_value toScript(pesapi_env env, Function value)
|
||||
{
|
||||
return pesapi_get_value_from_ref(env, value.value_holder);
|
||||
}
|
||||
|
||||
static Function toCpp(pesapi_env env, pesapi_value value)
|
||||
{
|
||||
return Function(env, value);
|
||||
}
|
||||
|
||||
static bool accept(pesapi_env env, pesapi_value value)
|
||||
{
|
||||
return pesapi_is_function(env, value);
|
||||
}
|
||||
};
|
||||
|
||||
#include "StdFunctionConverter.hpp"
|
||||
} // namespace pesapi_impl
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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 "Runtime/Launch/Resources/Version.h"
|
||||
|
||||
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
|
||||
#define PropertyMacro FProperty
|
||||
|
||||
#define NumericPropertyMacro FNumericProperty
|
||||
|
||||
#define BytePropertyMacro FByteProperty
|
||||
|
||||
#define Int8PropertyMacro FInt8Property
|
||||
|
||||
#define Int16PropertyMacro FInt16Property
|
||||
|
||||
#define IntPropertyMacro FIntProperty
|
||||
|
||||
#define Int64PropertyMacro FInt64Property
|
||||
|
||||
#define UInt16PropertyMacro FUInt16Property
|
||||
|
||||
#define UInt32PropertyMacro FUInt32Property
|
||||
|
||||
#define UInt64PropertyMacro FUInt64Property
|
||||
|
||||
#define FloatPropertyMacro FFloatProperty
|
||||
|
||||
#define DoublePropertyMacro FDoubleProperty
|
||||
|
||||
#define BoolPropertyMacro FBoolProperty
|
||||
|
||||
#define ObjectPropertyBaseMacro FObjectPropertyBase
|
||||
|
||||
#define ObjectPropertyMacro FObjectProperty
|
||||
|
||||
#define WeakObjectPropertyMacro FWeakObjectProperty
|
||||
|
||||
#define LazyObjectPropertyMacro FLazyObjectProperty
|
||||
|
||||
#define SoftObjectPropertyMacro FSoftObjectProperty
|
||||
|
||||
#define ClassPropertyMacro FClassProperty
|
||||
|
||||
#define SoftClassPropertyMacro FSoftClassProperty
|
||||
|
||||
#define InterfacePropertyMacro FInterfaceProperty
|
||||
|
||||
#define NamePropertyMacro FNameProperty
|
||||
|
||||
#define StrPropertyMacro FStrProperty
|
||||
|
||||
#define ArrayPropertyMacro FArrayProperty
|
||||
|
||||
#define MapPropertyMacro FMapProperty
|
||||
|
||||
#define SetPropertyMacro FSetProperty
|
||||
|
||||
#define StructPropertyMacro FStructProperty
|
||||
|
||||
#define DelegatePropertyMacro FDelegateProperty
|
||||
|
||||
#define MulticastDelegatePropertyMacro FMulticastDelegateProperty
|
||||
|
||||
#define MulticastInlineDelegatePropertyMacro FMulticastInlineDelegateProperty
|
||||
|
||||
#define MulticastSparseDelegatePropertyMacro FMulticastSparseDelegateProperty
|
||||
|
||||
#define EnumPropertyMacro FEnumProperty
|
||||
|
||||
#define TextPropertyMacro FTextProperty
|
||||
|
||||
#define CastFieldMacro CastField
|
||||
#else
|
||||
#define PropertyMacro UProperty
|
||||
|
||||
#define NumericPropertyMacro UNumericProperty
|
||||
|
||||
#define BytePropertyMacro UByteProperty
|
||||
|
||||
#define Int8PropertyMacro UInt8Property
|
||||
|
||||
#define Int16PropertyMacro UInt16Property
|
||||
|
||||
#define IntPropertyMacro UIntProperty
|
||||
|
||||
#define Int64PropertyMacro UInt64Property
|
||||
|
||||
#define UInt16PropertyMacro UUInt16Property
|
||||
|
||||
#define UInt32PropertyMacro UUInt32Property
|
||||
|
||||
#define UInt64PropertyMacro UUInt64Property
|
||||
|
||||
#define FloatPropertyMacro UFloatProperty
|
||||
|
||||
#define DoublePropertyMacro UDoubleProperty
|
||||
|
||||
#define BoolPropertyMacro UBoolProperty
|
||||
|
||||
#define ObjectPropertyBaseMacro UObjectPropertyBase
|
||||
|
||||
#define ObjectPropertyMacro UObjectProperty
|
||||
|
||||
#define WeakObjectPropertyMacro UWeakObjectProperty
|
||||
|
||||
#define LazyObjectPropertyMacro ULazyObjectProperty
|
||||
|
||||
#define SoftObjectPropertyMacro USoftObjectProperty
|
||||
|
||||
#define ClassPropertyMacro UClassProperty
|
||||
|
||||
#define SoftClassPropertyMacro USoftClassProperty
|
||||
|
||||
#define InterfacePropertyMacro UInterfaceProperty
|
||||
|
||||
#define NamePropertyMacro UNameProperty
|
||||
|
||||
#define StrPropertyMacro UStrProperty
|
||||
|
||||
#define ArrayPropertyMacro UArrayProperty
|
||||
|
||||
#define MapPropertyMacro UMapProperty
|
||||
|
||||
#define SetPropertyMacro USetProperty
|
||||
|
||||
#define StructPropertyMacro UStructProperty
|
||||
|
||||
#define DelegatePropertyMacro UDelegateProperty
|
||||
|
||||
#define MulticastDelegatePropertyMacro UMulticastDelegateProperty
|
||||
|
||||
#define MulticastInlineDelegatePropertyMacro UMulticastInlineDelegateProperty
|
||||
|
||||
#define MulticastSparseDelegatePropertyMacro UMulticastSparseDelegateProperty
|
||||
|
||||
#define EnumPropertyMacro UEnumProperty
|
||||
|
||||
#define TextPropertyMacro UTextProperty
|
||||
|
||||
#define CastFieldMacro Cast
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#if !defined(PUERTS_NAMESPACE)
|
||||
#if defined(WITH_QJS_NAMESPACE_SUFFIX)
|
||||
#define PUERTS_NAMESPACE puerts_qjs
|
||||
#else
|
||||
#define PUERTS_NAMESPACE puerts
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
|
||||
#if defined(_MSC_VER)
|
||||
#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS __pragma(warning(push)) __pragma(warning(disable : 4668))
|
||||
#elif defined(__clang__)
|
||||
#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS \
|
||||
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wundef\"")
|
||||
#elif defined(__GNUC__)
|
||||
#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wundef\"")
|
||||
#endif
|
||||
#endif // PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
|
||||
|
||||
#ifndef PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
|
||||
#if defined(_MSC_VER)
|
||||
#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS __pragma(warning(pop))
|
||||
#elif defined(__clang__)
|
||||
#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("clang diagnostic pop")
|
||||
#elif defined(__GNUC__)
|
||||
#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
#endif // PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
|
||||
|
||||
#ifndef MSVC_PRAGMA
|
||||
#if !defined(__clang__) && defined(_MSC_VER)
|
||||
#define MSVC_PRAGMA(Pragma) __pragma(Pragma)
|
||||
#else
|
||||
#define MSVC_PRAGMA(...)
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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
|
||||
#if defined(BUILDING_PES_EXTENSION)
|
||||
#include "PesapiBackend.hpp"
|
||||
#endif
|
||||
#if !defined(BUILDING_PES_EXTENSION) || defined(PES_EXTENSION_WITH_V8_API)
|
||||
#include "V8Backend.hpp"
|
||||
#endif
|
||||
#include "Object.hpp"
|
||||
|
||||
#ifndef PUERTS_BINDING_IMPL
|
||||
#if defined(BUILDING_PES_EXTENSION) && !defined(PES_EXTENSION_WITH_V8_API)
|
||||
#define PUERTS_BINDING_IMPL pesapi_impl
|
||||
#else
|
||||
#define PUERTS_BINDING_IMPL v8_impl
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MakeConstructor(T, ...) \
|
||||
::PUERTS_NAMESPACE::template ConstructorWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, T, ##__VA_ARGS__>
|
||||
#define MakeGetter(M) &(::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::getter)
|
||||
#define MakeSetter(M) &(::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::setter)
|
||||
#define MakeProperty(M) \
|
||||
&(::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::getter), \
|
||||
&(::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::setter), \
|
||||
::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::info()
|
||||
#define MakeReadonlyProperty(M) \
|
||||
&(::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::getter), nullptr, \
|
||||
::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::info()
|
||||
#define MakeVariable(M) MakeProperty(M)
|
||||
#define MakeReadonlyVariable(M) MakeReadonlyProperty(M)
|
||||
#define MakeFunction(M, ...) \
|
||||
[](::PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \
|
||||
{ \
|
||||
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::callWithDefaultValues( \
|
||||
info, ##__VA_ARGS__); \
|
||||
}, \
|
||||
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::info( \
|
||||
PUERTS_NAMESPACE::Count(__VA_ARGS__))
|
||||
#define MakeExtension(M, ...) \
|
||||
[](::PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \
|
||||
{ \
|
||||
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), \
|
||||
M>::callExtensionWithDefaultValues(info, ##__VA_ARGS__); \
|
||||
}, \
|
||||
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::extensionInfo( \
|
||||
PUERTS_NAMESPACE::Count(__VA_ARGS__))
|
||||
#define SelectFunction(SIGNATURE, M, ...) \
|
||||
[](::PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \
|
||||
{ \
|
||||
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M>::callWithDefaultValues( \
|
||||
info, ##__VA_ARGS__); \
|
||||
}, \
|
||||
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M>::info( \
|
||||
PUERTS_NAMESPACE::Count(__VA_ARGS__))
|
||||
#define SelectFunction_PtrRet(SIGNATURE, M, ...) \
|
||||
[](::PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \
|
||||
{ \
|
||||
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M, \
|
||||
true>::callWithDefaultValues(info, ##__VA_ARGS__); \
|
||||
}, \
|
||||
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M, true>::info( \
|
||||
PUERTS_NAMESPACE::Count(__VA_ARGS__))
|
||||
#define MakeCheckFunction(M) \
|
||||
&(::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::checkedCall), \
|
||||
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::info()
|
||||
#define MakeOverload(SIGNATURE, M) PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M>
|
||||
#define CombineOverloads(...) \
|
||||
&::PUERTS_NAMESPACE::OverloadsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::call, \
|
||||
::PUERTS_NAMESPACE::OverloadsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::length, \
|
||||
::PUERTS_NAMESPACE::OverloadsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::infos()
|
||||
#define CombineConstructors(...) \
|
||||
&::PUERTS_NAMESPACE::ConstructorsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::call, \
|
||||
::PUERTS_NAMESPACE::ConstructorsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::length, \
|
||||
::PUERTS_NAMESPACE::ConstructorsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::infos()
|
||||
|
||||
#define DeclOverloads(Name) \
|
||||
template <typename T> \
|
||||
struct Name##PuertsOverloads \
|
||||
{ \
|
||||
};
|
||||
|
||||
#define DeclOverload(Name, SIGNATURE, M, ...) \
|
||||
template <> \
|
||||
struct Name##PuertsOverloads<SIGNATURE> \
|
||||
{ \
|
||||
static bool overloadCall(::PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \
|
||||
{ \
|
||||
return ::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M, \
|
||||
true>::overloadCallWithDefaultValues(info, ##__VA_ARGS__); \
|
||||
} \
|
||||
static const ::PUERTS_NAMESPACE::CFunctionInfo* info() \
|
||||
{ \
|
||||
return ::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M>::info( \
|
||||
PUERTS_NAMESPACE::Count(__VA_ARGS__)); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define SelectOverload(Name, SIGNATURE) Name##PuertsOverloads<SIGNATURE>
|
||||
|
||||
#define __DefObjectType_HELPER1(CLS, Suffix) __DefObjectType_##Suffix(CLS)
|
||||
#define __DefObjectType_HELPER2(CLS, Suffix) __DefObjectType_HELPER1(CLS, Suffix)
|
||||
#define __DefCDataPointerConverter_HELPER1(CLS, Suffix) __DefCDataPointerConverter_##Suffix(CLS)
|
||||
#define __DefCDataPointerConverter_HELPER2(CLS, Suffix) __DefCDataPointerConverter_HELPER1(CLS, Suffix)
|
||||
#define __DefObjectType(CLS) __DefObjectType_HELPER2(CLS, PUERTS_BINDING_IMPL)
|
||||
#define __DefCDataPointerConverter(CLS) __DefCDataPointerConverter_HELPER2(CLS, PUERTS_BINDING_IMPL)
|
||||
#define UsingNamedCppType(CLS, NAME) __DefScriptTTypeName(NAME, CLS) __DefObjectType(CLS) __DefCDataPointerConverter(CLS)
|
||||
|
||||
#define UsingCppType(CLS) UsingNamedCppType(CLS, CLS)
|
||||
|
||||
#if defined(BUILDING_PES_EXTENSION) && !defined(PES_EXTENSION_WITH_V8_API)
|
||||
#define UsingOtherModuleCppType(MODULE, CLS) \
|
||||
namespace PUERTS_NAMESPACE \
|
||||
{ \
|
||||
template <> \
|
||||
struct StaticTypeId<CLS> \
|
||||
{ \
|
||||
static const void* get() \
|
||||
{ \
|
||||
static void* cache_type_id = nullptr; \
|
||||
if (!cache_type_id) \
|
||||
{ \
|
||||
cache_type_id = (void*) pesapi_find_type_id(#MODULE, #CLS); \
|
||||
} \
|
||||
return cache_type_id; \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
UsingNamedCppType(CLS, CLS)
|
||||
#endif
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
template <typename T, typename API, typename RegisterAPI>
|
||||
class ClassDefineBuilder;
|
||||
|
||||
#if defined(BUILDING_PES_EXTENSION)
|
||||
template <typename T>
|
||||
ClassDefineBuilder<T, PUERTS_BINDING_IMPL::API, pesapi_impl::API> DefineClass()
|
||||
{
|
||||
static auto NameLiteral = ScriptTypeName<T>::value();
|
||||
return ClassDefineBuilder<T, PUERTS_BINDING_IMPL::API, pesapi_impl::API>(NameLiteral.Data());
|
||||
}
|
||||
#else
|
||||
template <typename T>
|
||||
ClassDefineBuilder<T, PUERTS_BINDING_IMPL::API, PUERTS_BINDING_IMPL::API> DefineClass()
|
||||
{
|
||||
static auto NameLiteral = ScriptTypeName<T>::value();
|
||||
return ClassDefineBuilder<T, PUERTS_BINDING_IMPL::API, PUERTS_BINDING_IMPL::API>(NameLiteral.Data());
|
||||
}
|
||||
#endif
|
||||
|
||||
using Object = PUERTS_BINDING_IMPL::Object;
|
||||
|
||||
using Function = PUERTS_BINDING_IMPL::Function;
|
||||
|
||||
inline void ThrowException(const char* msg)
|
||||
{
|
||||
internal::ExceptionHandle<PUERTS_BINDING_IMPL::API>::Throw(msg);
|
||||
}
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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
|
||||
#if WITH_EDITOR
|
||||
#include "CoreMinimal.h"
|
||||
#include "IDirectoryWatcher.h"
|
||||
#include "Misc/SecureHash.h"
|
||||
#include <functional>
|
||||
#include "PuertsNamespaceDef.h"
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
class JSENV_API FSourceFileWatcher
|
||||
{
|
||||
public:
|
||||
FSourceFileWatcher(std::function<void(const FString&)> InOnWatchedFileChanged);
|
||||
|
||||
~FSourceFileWatcher();
|
||||
|
||||
void OnSourceLoaded(const FString& InPath);
|
||||
|
||||
void OnDirectoryChanged(const TArray<FFileChangeData>& FileChanges);
|
||||
|
||||
private:
|
||||
TMap<FString, FDelegateHandle> WatchedDirs;
|
||||
|
||||
TMap<FString, TMap<FString, FMD5Hash>> WatchedFiles;
|
||||
|
||||
FCriticalSection SourceFileWatcherCritical;
|
||||
|
||||
std::function<void(const FString&)> OnWatchedFileChanged;
|
||||
};
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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
|
||||
template <typename R, typename... Args>
|
||||
struct Converter<std::function<R(Args...)>>
|
||||
{
|
||||
static API::ValueType toScript(API::ContextType context, std::function<R(Args...)> value)
|
||||
{
|
||||
return API::GetUndefined(context);
|
||||
}
|
||||
|
||||
static std::function<R(Args...)> toCpp(API::ContextType context, const API::ValueType value)
|
||||
{
|
||||
if (API::IsNullOrUndefined(context, value))
|
||||
return nullptr;
|
||||
Function PF(context, value);
|
||||
return [=](Args... cppArgs) -> R { return PF.Func<R>(cppArgs...); };
|
||||
}
|
||||
|
||||
static bool accept(API::ContextType context, const API::ValueType value)
|
||||
{
|
||||
return API::IsNullOrUndefined(context, value) || Converter<Function>::accept(context, value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
struct Converter<std::function<void(Args...)>>
|
||||
{
|
||||
static API::ValueType toScript(API::ContextType context, std::function<void(Args...)> value)
|
||||
{
|
||||
return API::GetUndefined(context);
|
||||
}
|
||||
|
||||
static std::function<void(Args...)> toCpp(API::ContextType context, const API::ValueType value)
|
||||
{
|
||||
if (API::IsNullOrUndefined(context, value))
|
||||
return nullptr;
|
||||
Function PF(context, value);
|
||||
return [=](Args... cppArgs) -> void { PF.Action(cppArgs...); };
|
||||
}
|
||||
|
||||
static bool accept(API::ContextType context, const API::ValueType value)
|
||||
{
|
||||
return API::IsNullOrUndefined(context, value) || Converter<Function>::accept(context, value);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 "UObject/Stack.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "UObject/Class.h"
|
||||
#include "PuertsNamespaceDef.h"
|
||||
|
||||
class UTypeScriptGeneratedClass;
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
class ITsDynamicInvoker
|
||||
{
|
||||
public:
|
||||
virtual void TsConstruct(UTypeScriptGeneratedClass* Class, UObject* Object) = 0;
|
||||
|
||||
virtual void InvokeTsMethod(UObject* ContextObject, UFunction* Function, FFrame& Stack, void* RESULT_PARAM) = 0;
|
||||
|
||||
virtual void NotifyReBind(UTypeScriptGeneratedClass* Class) = 0;
|
||||
};
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,536 @@
|
||||
/*
|
||||
* 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 <string>
|
||||
#ifdef WITH_V8_FAST_CALL
|
||||
#include "V8FastCall.hpp"
|
||||
#endif
|
||||
#include "PuertsNamespaceDef.h"
|
||||
|
||||
#define __DefScriptTTypeName(CLSNAME, CLS) \
|
||||
namespace PUERTS_NAMESPACE \
|
||||
{ \
|
||||
template <> \
|
||||
struct ScriptTypeName<CLS> \
|
||||
{ \
|
||||
static constexpr auto value() \
|
||||
{ \
|
||||
return internal::Literal(#CLSNAME); \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
#define PUERTS_BINDING_PROTO_ID() "fdq4falqlqcq"
|
||||
|
||||
#if defined(WITH_QJS_NAMESPACE_SUFFIX)
|
||||
namespace v8_qjs
|
||||
{
|
||||
class CFunction;
|
||||
}
|
||||
|
||||
namespace v8 = v8_qjs;
|
||||
#else
|
||||
namespace v8
|
||||
{
|
||||
class CFunction;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
template <std::size_t N>
|
||||
class StringLiteral
|
||||
{
|
||||
public:
|
||||
template <typename... Characters>
|
||||
constexpr StringLiteral(Characters... characters) : m_value{characters..., '\0'}
|
||||
{
|
||||
}
|
||||
|
||||
template <std::size_t... Indexes>
|
||||
constexpr StringLiteral(const char (&value)[N + 1], std::index_sequence<Indexes...> dummy) : StringLiteral(value[Indexes]...)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr StringLiteral(const char (&value)[N + 1]) : StringLiteral(value, std::make_index_sequence<N>{})
|
||||
{
|
||||
}
|
||||
|
||||
constexpr char operator[](const std::size_t index) const
|
||||
{
|
||||
return m_value[index];
|
||||
}
|
||||
|
||||
constexpr const char* Data() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
template <std::size_t Start, std::size_t... Index>
|
||||
constexpr StringLiteral<N - Start> Sub(std::index_sequence<Index...> dummy) const
|
||||
{
|
||||
return StringLiteral<N - Start>(m_value[Start + Index]...);
|
||||
}
|
||||
|
||||
template <std::size_t Start>
|
||||
constexpr StringLiteral<N - Start> Sub() const
|
||||
{
|
||||
return Sub<Start>(std::make_index_sequence<N - Start>());
|
||||
}
|
||||
|
||||
private:
|
||||
const char m_value[N + 1];
|
||||
};
|
||||
|
||||
template <typename Left, typename Right, std::size_t... IndexesLeft, std::size_t... IndexesRight>
|
||||
constexpr StringLiteral<sizeof...(IndexesLeft) + sizeof...(IndexesRight)> ConcatStrings(
|
||||
const Left& lhs, const Right& rhs, std::index_sequence<IndexesLeft...> dummy1, std::index_sequence<IndexesRight...> dummy2)
|
||||
{
|
||||
return StringLiteral<sizeof...(IndexesLeft) + sizeof...(IndexesRight)>(lhs[IndexesLeft]..., rhs[IndexesRight]...);
|
||||
}
|
||||
|
||||
template <std::size_t X, std::size_t Y>
|
||||
constexpr StringLiteral<X + Y> operator+(const StringLiteral<X>& lhs, const StringLiteral<Y>& rhs)
|
||||
{
|
||||
return ConcatStrings(lhs, rhs, std::make_index_sequence<X>(), std::make_index_sequence<Y>());
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr auto Literal(const char (&value)[N])
|
||||
{
|
||||
return StringLiteral<N - 1>(value, typename std::make_index_sequence<N - 1>{});
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct ScriptTypeName
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct ScriptTypeNameWithNamespace
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return ScriptTypeName<T>::value();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScriptTypeName<T*>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return ScriptTypeName<typename std::remove_cv<T>::type>::value();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScriptTypeName<T&>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return ScriptTypeName<typename std::remove_cv<T>::type>::value();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScriptTypeName<T&&>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return ScriptTypeName<typename std::remove_cv<T>::type>::value();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScriptTypeName<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 8>::type>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("bigint");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScriptTypeName<T, typename std::enable_if<std::is_enum<T>::value>::type>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("number");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScriptTypeName<T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value || (std::is_integral<T>::value && sizeof(T) < 8)>::type>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("number");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<std::string>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("string");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<const char*>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("cstring");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<bool>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("boolean");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<void>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("void");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct StaticTypeId
|
||||
{
|
||||
static const void* get()
|
||||
{
|
||||
static T* dummy = nullptr;
|
||||
return &dummy;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct DynamicTypeId
|
||||
{
|
||||
static const void* get(T* Obj)
|
||||
{
|
||||
return StaticTypeId<T>::get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_uetype : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_objecttype : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct is_script_type : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_script_type<T, typename std::enable_if<std::is_fundamental<T>::value && !std::is_same<T, void>::value>::type>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_script_type<std::string> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, size_t Size>
|
||||
struct ScriptTypeName<T[Size], typename std::enable_if<is_script_type<T>::value && !std::is_const<T>::value>::type>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("ArrayBuffer");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<void*>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("any");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<const void*>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("any");
|
||||
}
|
||||
};
|
||||
|
||||
class CTypeInfo
|
||||
{
|
||||
public:
|
||||
virtual const char* Name() const = 0;
|
||||
virtual bool IsPointer() const = 0;
|
||||
virtual bool IsRef() const = 0;
|
||||
virtual bool IsConst() const = 0;
|
||||
virtual bool IsUEType() const = 0;
|
||||
virtual bool IsObjectType() const = 0;
|
||||
};
|
||||
|
||||
class CFunctionInfo
|
||||
{
|
||||
public:
|
||||
virtual const CTypeInfo* Return() const = 0;
|
||||
virtual unsigned int ArgumentCount() const = 0;
|
||||
virtual unsigned int DefaultCount() const = 0;
|
||||
virtual const CTypeInfo* Argument(unsigned int index) const = 0;
|
||||
virtual const char* CustomSignature() const = 0;
|
||||
virtual const class v8::CFunction* FastCallInfo() const = 0;
|
||||
};
|
||||
|
||||
template <typename T, bool ScriptTypePtrAsRef>
|
||||
class CTypeInfoImpl : CTypeInfo
|
||||
{
|
||||
public:
|
||||
virtual const char* Name() const override
|
||||
{
|
||||
static auto NameLiteral = ScriptTypeName<T>::value();
|
||||
return NameLiteral.Data();
|
||||
}
|
||||
virtual bool IsPointer() const override
|
||||
{
|
||||
return std::is_pointer<T>::value && !ScriptTypePtrAsRef;
|
||||
};
|
||||
virtual bool IsRef() const override
|
||||
{
|
||||
return (std::is_reference<T>::value && !std::is_const<typename std::remove_reference<T>::type>::value) ||
|
||||
(std::is_pointer<T>::value &&
|
||||
!std::is_same<void, typename std::decay<typename std::remove_pointer<T>::type>::type>::value &&
|
||||
!std::is_same<char, typename std::decay<typename std::remove_pointer<T>::type>::type>::value &&
|
||||
ScriptTypePtrAsRef && !IsUEType() && !IsObjectType());
|
||||
};
|
||||
virtual bool IsConst() const override
|
||||
{
|
||||
return std::is_const<typename std::remove_pointer<typename std::decay<T>::type>::type>::value;
|
||||
};
|
||||
virtual bool IsUEType() const override
|
||||
{
|
||||
return is_uetype<typename std::remove_const<typename std::remove_pointer<typename std::decay<T>::type>::type>::type>::value;
|
||||
};
|
||||
virtual bool IsObjectType() const override
|
||||
{
|
||||
return is_objecttype<
|
||||
typename std::remove_const<typename std::remove_pointer<typename std::decay<T>::type>::type>::type>::value;
|
||||
};
|
||||
|
||||
static const CTypeInfo* get()
|
||||
{
|
||||
static CTypeInfoImpl instance;
|
||||
return &instance;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Ret, bool ScriptTypePtrAsRef, std::size_t StartParameter, typename... Args>
|
||||
class CFunctionInfoImpl : public CFunctionInfo
|
||||
{
|
||||
protected:
|
||||
const CTypeInfo* return_;
|
||||
const unsigned int argCount_;
|
||||
const CTypeInfo* arguments_[sizeof...(Args) + 1];
|
||||
unsigned int defaultCount_;
|
||||
|
||||
CFunctionInfoImpl()
|
||||
: return_(CTypeInfoImpl<Ret, ScriptTypePtrAsRef>::get())
|
||||
, argCount_(sizeof...(Args))
|
||||
, arguments_{CTypeInfoImpl<Args, ScriptTypePtrAsRef>::get()...}
|
||||
, defaultCount_(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CFunctionInfoImpl()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual const CTypeInfo* Return() const override
|
||||
{
|
||||
return return_;
|
||||
}
|
||||
virtual unsigned int ArgumentCount() const override
|
||||
{
|
||||
return argCount_ - StartParameter;
|
||||
}
|
||||
virtual unsigned int DefaultCount() const override
|
||||
{
|
||||
return defaultCount_;
|
||||
}
|
||||
virtual const CTypeInfo* Argument(unsigned int index) const override
|
||||
{
|
||||
return arguments_[index + StartParameter];
|
||||
}
|
||||
virtual const char* CustomSignature() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual const class v8::CFunction* FastCallInfo() const override
|
||||
{
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
static const CFunctionInfo* get(unsigned int defaultCount)
|
||||
{
|
||||
static CFunctionInfoImpl instance{};
|
||||
instance.defaultCount_ = defaultCount;
|
||||
return &instance;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, T, bool, std::size_t StartParameter = 0>
|
||||
class CFunctionInfoByPtrImpl
|
||||
{
|
||||
};
|
||||
|
||||
template <typename Ret, typename... Args, Ret (*func)(Args...), bool ScriptTypePtrAsRef, std::size_t StartParameter>
|
||||
class CFunctionInfoByPtrImpl<Ret (*)(Args...), func, ScriptTypePtrAsRef, StartParameter>
|
||||
: public CFunctionInfoImpl<Ret, ScriptTypePtrAsRef, StartParameter, Args...>
|
||||
{
|
||||
public:
|
||||
virtual ~CFunctionInfoByPtrImpl()
|
||||
{
|
||||
}
|
||||
#ifdef WITH_V8_FAST_CALL
|
||||
virtual const class v8::CFunction* FastCallInfo() const override
|
||||
{
|
||||
return V8FastCall<Ret (*)(Args...), func>::info();
|
||||
};
|
||||
#endif
|
||||
|
||||
static const CFunctionInfo* get(unsigned int defaultCount)
|
||||
{
|
||||
static CFunctionInfoByPtrImpl instance{};
|
||||
instance.defaultCount_ = defaultCount;
|
||||
return &instance;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Inc, typename Ret, typename... Args, Ret (Inc::*func)(Args...), bool ScriptTypePtrAsRef>
|
||||
class CFunctionInfoByPtrImpl<Ret (Inc::*)(Args...), func, ScriptTypePtrAsRef>
|
||||
: public CFunctionInfoImpl<Ret, ScriptTypePtrAsRef, 0, Args...>
|
||||
{
|
||||
public:
|
||||
virtual ~CFunctionInfoByPtrImpl()
|
||||
{
|
||||
}
|
||||
#ifdef WITH_V8_FAST_CALL
|
||||
virtual const class v8::CFunction* FastCallInfo() const override
|
||||
{
|
||||
return V8FastCall<Ret (Inc::*)(Args...), func>::info();
|
||||
};
|
||||
#endif
|
||||
|
||||
static const CFunctionInfo* get(unsigned int defaultCount)
|
||||
{
|
||||
static CFunctionInfoByPtrImpl instance{};
|
||||
instance.defaultCount_ = defaultCount;
|
||||
return &instance;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Inc, typename Ret, typename... Args, Ret (Inc::*func)(Args...) const, bool ScriptTypePtrAsRef>
|
||||
class CFunctionInfoByPtrImpl<Ret (Inc::*)(Args...) const, func, ScriptTypePtrAsRef>
|
||||
: public CFunctionInfoImpl<Ret, ScriptTypePtrAsRef, 0, Args...>
|
||||
{
|
||||
public:
|
||||
virtual ~CFunctionInfoByPtrImpl()
|
||||
{
|
||||
}
|
||||
#ifdef WITH_V8_FAST_CALL
|
||||
virtual const class v8::CFunction* FastCallInfo() const override
|
||||
{
|
||||
return V8FastCall<Ret (Inc::*)(Args...) const, func>::info();
|
||||
};
|
||||
#endif
|
||||
|
||||
static const CFunctionInfo* get(unsigned int defaultCount)
|
||||
{
|
||||
static CFunctionInfoByPtrImpl instance{};
|
||||
instance.defaultCount_ = defaultCount;
|
||||
return &instance;
|
||||
}
|
||||
};
|
||||
|
||||
class CFunctionInfoWithCustomSignature : public CFunctionInfo
|
||||
{
|
||||
const char* _signature;
|
||||
|
||||
public:
|
||||
CFunctionInfoWithCustomSignature(const char* signature) : _signature(signature)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CFunctionInfoWithCustomSignature()
|
||||
{
|
||||
}
|
||||
|
||||
virtual const CTypeInfo* Return() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual unsigned int ArgumentCount() const override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual unsigned int DefaultCount() const override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual const CTypeInfo* Argument(unsigned int index) const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual const char* CustomSignature() const override
|
||||
{
|
||||
return _signature;
|
||||
}
|
||||
virtual const class v8::CFunction* FastCallInfo() const override
|
||||
{
|
||||
return nullptr;
|
||||
};
|
||||
};
|
||||
|
||||
struct NamedFunctionInfo
|
||||
{
|
||||
const char* Name;
|
||||
const CFunctionInfo* Type;
|
||||
};
|
||||
|
||||
struct NamedPropertyInfo
|
||||
{
|
||||
const char* Name;
|
||||
const CTypeInfo* Type;
|
||||
};
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 "CoreMinimal.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "TypeScriptBlueprint.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class JSENV_API UTypeScriptBlueprint : public UBlueprint
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
#if WITH_EDITOR
|
||||
virtual UClass* GetBlueprintClass() const override;
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 "TsDynamicInvoker.h"
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/BlueprintGeneratedClass.h"
|
||||
#include "Templates/Function.h"
|
||||
#include "Templates/SharedPointer.h"
|
||||
#include "Runtime/CoreUObject/Public/UObject/Package.h"
|
||||
|
||||
#include "TypeScriptGeneratedClass.generated.h"
|
||||
|
||||
struct PendingConstructJobInfo
|
||||
{
|
||||
TFunction<void()> Func = nullptr;
|
||||
TSharedPtr<int> Ref = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class JSENV_API UTypeScriptGeneratedClass : public UBlueprintGeneratedClass
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
TWeakPtr<PUERTS_NAMESPACE::ITsDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker;
|
||||
|
||||
TSet<FName> FunctionToRedirect;
|
||||
|
||||
bool RedirectedToTypeScript = false;
|
||||
|
||||
TMap<FName, FNativeFuncPtr> TempNativeFuncStorage;
|
||||
|
||||
#if WITH_EDITOR
|
||||
bool NeedReBind = true;
|
||||
TSet<TWeakObjectPtr<UObject>> GeneratedObjects;
|
||||
bool FunctionToRedirectInitialized = false;
|
||||
static void NotifyRebind(UClass* Class);
|
||||
void LazyLoadRedirect();
|
||||
#endif
|
||||
|
||||
DECLARE_FUNCTION(execLazyLoadCallJS);
|
||||
|
||||
static void StaticConstructor(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
void ObjectInitialize(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
virtual void Bind() override;
|
||||
|
||||
void RedirectToTypeScript(UFunction* InFunction);
|
||||
|
||||
void RedirectToTypeScriptFinish();
|
||||
|
||||
void CancelRedirection();
|
||||
|
||||
bool NotSupportInject();
|
||||
|
||||
void RestoreNativeFunc();
|
||||
|
||||
UPROPERTY()
|
||||
bool HasConstructor;
|
||||
|
||||
DECLARE_FUNCTION(execCallJS);
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 "Runtime/Launch/Resources/Version.h"
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "UObject/UObjectIterator.h"
|
||||
#include "PuertsNamespaceDef.h"
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
FORCEINLINE bool UEObjectIsPendingKill(const UObject* Test)
|
||||
{
|
||||
#if ENGINE_MAJOR_VERSION > 4
|
||||
return !IsValid(Test) || Test->IsUnreachable();
|
||||
#else
|
||||
return Test->IsPendingKillOrUnreachable();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENGINE_MAJOR_VERSION > 4
|
||||
#define FUETicker FTSTicker
|
||||
#define FUETickDelegateHandle FTSTicker::FDelegateHandle
|
||||
#else
|
||||
#define FUETicker FTicker
|
||||
#define FUETickDelegateHandle FDelegateHandle
|
||||
#endif
|
||||
|
||||
#if ENGINE_MINOR_VERSION >= 27 || ENGINE_MAJOR_VERSION > 4
|
||||
typedef FThreadSafeObjectIterator FUEObjectIterator;
|
||||
#else
|
||||
typedef FObjectIterator FUEObjectIterator;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
T* FindAnyType(const TCHAR* InShortName)
|
||||
{
|
||||
#if (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1) || ENGINE_MAJOR_VERSION > 5
|
||||
return FindFirstObject<T>(
|
||||
InShortName, EFindFirstObjectOptions::EnsureIfAmbiguous | EFindFirstObjectOptions::NativeFirst, ELogVerbosity::Error);
|
||||
#else
|
||||
return FindObject<T>(ANY_PACKAGE, InShortName);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* FindAnyType(const FString& InShortName)
|
||||
{
|
||||
return FindAnyType<T>(*InShortName);
|
||||
}
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,534 @@
|
||||
/*
|
||||
* 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 "ScriptBackend.hpp"
|
||||
#include "DataTransfer.h"
|
||||
#include "ArrayBuffer.h"
|
||||
#include "UECompatible.h"
|
||||
#include "PuertsNamespaceDef.h"
|
||||
|
||||
#define UsingUClass(CLS) \
|
||||
namespace PUERTS_NAMESPACE \
|
||||
{ \
|
||||
template <> \
|
||||
struct ScriptTypeName<CLS> \
|
||||
{ \
|
||||
static constexpr auto value() \
|
||||
{ \
|
||||
return internal::Literal(#CLS).Sub<1>(); \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
namespace PUERTS_NAMESPACE \
|
||||
{ \
|
||||
template <> \
|
||||
struct is_uetype<CLS> : public std::true_type \
|
||||
{ \
|
||||
}; \
|
||||
}
|
||||
|
||||
#define UsingTArrayWithName(CLS, CLSNAME) \
|
||||
namespace PUERTS_NAMESPACE \
|
||||
{ \
|
||||
template <> \
|
||||
struct ScriptTypeName<TArray<CLS>> \
|
||||
{ \
|
||||
static constexpr auto value() \
|
||||
{ \
|
||||
return internal::Literal(CLSNAME); \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
__DefObjectType(TArray<CLS>) __DefCDataPointerConverter(TArray<CLS>)
|
||||
|
||||
#define UsingCrossModuleCppType(CLS) \
|
||||
namespace PUERTS_NAMESPACE \
|
||||
{ \
|
||||
template <> \
|
||||
struct StaticTypeId<CLS> \
|
||||
{ \
|
||||
static const void* get() \
|
||||
{ \
|
||||
static const void* cache_type_id = nullptr; \
|
||||
if (!cache_type_id) \
|
||||
{ \
|
||||
auto info = PUERTS_NAMESPACE::FindCppTypeClassByName(#CLS); \
|
||||
cache_type_id = info ? info->TypeId : &cache_type_id; \
|
||||
} \
|
||||
return cache_type_id; \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
UsingNamedCppType(CLS, CLS)
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 4
|
||||
#define RegisterTArray(CLS) \
|
||||
PUERTS_NAMESPACE::DefineClass<TArray<CLS>>() \
|
||||
.Method("Add", SelectFunction(int (TArray<CLS>::*)(CLS const&), &TArray<CLS>::Add)) \
|
||||
.Method("Get", SelectFunction(CLS& (TArray<CLS>::*) (int), &TArray<CLS>::operator[])) \
|
||||
.Method("GetRef", SelectFunction(CLS& (TArray<CLS>::*) (int), &TArray<CLS>::operator[])) \
|
||||
.Method("Num", MakeFunction(&TArray<CLS>::Num)) \
|
||||
.Method("Contains", MakeFunction(&TArray<CLS>::Contains<CLS>)) \
|
||||
.Method("FindIndex", SelectFunction(int (TArray<CLS>::*)(CLS const&) const, &TArray<CLS>::Find)) \
|
||||
.Method( \
|
||||
"RemoveAt", SelectFunction(void (TArray<CLS>::*)(int, /* New param in 5.4*/ EAllowShrinking), &TArray<CLS>::RemoveAt)) \
|
||||
.Method("IsValidIndex", MakeFunction(&TArray<CLS>::IsValidIndex)) \
|
||||
.Method("Empty", MakeFunction(&TArray<CLS>::Empty)) \
|
||||
.Register()
|
||||
#else
|
||||
#define RegisterTArray(CLS) \
|
||||
PUERTS_NAMESPACE::DefineClass<TArray<CLS>>() \
|
||||
.Method("Add", SelectFunction(int (TArray<CLS>::*)(CLS const&), &TArray<CLS>::Add)) \
|
||||
.Method("Get", SelectFunction(CLS& (TArray<CLS>::*) (int), &TArray<CLS>::operator[])) \
|
||||
.Method("GetRef", SelectFunction(CLS& (TArray<CLS>::*) (int), &TArray<CLS>::operator[])) \
|
||||
.Method("Num", MakeFunction(&TArray<CLS>::Num)) \
|
||||
.Method("Contains", MakeFunction(&TArray<CLS>::Contains<CLS>)) \
|
||||
.Method("FindIndex", SelectFunction(int (TArray<CLS>::*)(CLS const&) const, &TArray<CLS>::Find)) \
|
||||
.Method("RemoveAt", SelectFunction(void (TArray<CLS>::*)(int), &TArray<CLS>::RemoveAt)) \
|
||||
.Method("IsValidIndex", MakeFunction(&TArray<CLS>::IsValidIndex)) \
|
||||
.Method("Empty", MakeFunction(&TArray<CLS>::Empty)) \
|
||||
.Register()
|
||||
#endif
|
||||
|
||||
#define UsingUStruct(CLS) UsingUClass(CLS)
|
||||
|
||||
#define UsingContainer(CLS) __DefObjectType(CLS) __DefCDataPointerConverter(CLS)
|
||||
|
||||
#define UsingTSharedPtr(ITEMCLS) __DefObjectType(TSharedPtr<ITEMCLS>) __DefCDataPointerConverter(TSharedPtr<ITEMCLS>)
|
||||
|
||||
template <class T>
|
||||
struct TSharedPtrExtension
|
||||
{
|
||||
static bool Equals(const TSharedPtr<T> Lhs, const TSharedPtr<T> Rhs)
|
||||
{
|
||||
return Lhs == Rhs;
|
||||
}
|
||||
};
|
||||
|
||||
#define RegisterTSharedPtr(ITEMCLS) \
|
||||
PUERTS_NAMESPACE::DefineClass<TSharedPtr<ITEMCLS>>() \
|
||||
.Method("Equals", MakeExtension(&TSharedPtrExtension<ITEMCLS>::Equals)) \
|
||||
.Register();
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
namespace v8_impl
|
||||
{
|
||||
class TCharStringHolder
|
||||
{
|
||||
public:
|
||||
TCharStringHolder()
|
||||
{
|
||||
}
|
||||
|
||||
TCharStringHolder(v8::Local<v8::Context> context, const v8::Local<v8::Value> value)
|
||||
{
|
||||
Str = FV8Utils::ToFString(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
const TCHAR* Data() const
|
||||
{
|
||||
return *Str;
|
||||
}
|
||||
|
||||
private:
|
||||
FString Str;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct CustomArgumentBufferType<const TCHAR*>
|
||||
{
|
||||
using type = TCharStringHolder;
|
||||
static constexpr bool enable = true;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<FString>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FString value)
|
||||
{
|
||||
return FV8Utils::ToV8String(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
static FString toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return FV8Utils::ToFString(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsString();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<FName>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FName value)
|
||||
{
|
||||
return FV8Utils::ToV8String(context->GetIsolate(), value.ToString());
|
||||
}
|
||||
|
||||
static FName toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
if (value->IsArrayBuffer())
|
||||
{
|
||||
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
|
||||
size_t ByteLength;
|
||||
auto Data = DataTransfer::GetArrayBufferData(Ab, ByteLength);
|
||||
if (ByteLength == sizeof(FName))
|
||||
{
|
||||
return *static_cast<FName*>(Data);
|
||||
}
|
||||
}
|
||||
return FV8Utils::ToFName(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsString();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<const TCHAR*>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const TCHAR* value)
|
||||
{
|
||||
return FV8Utils::ToV8String(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
static TCharStringHolder toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return TCharStringHolder(context, value);
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsString();
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef PUERTS_FTEXT_AS_OBJECT
|
||||
template <>
|
||||
struct Converter<FText>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FText value)
|
||||
{
|
||||
return FV8Utils::ToV8String(context->GetIsolate(), value.ToString());
|
||||
}
|
||||
|
||||
static FText toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return FText::FromString(FV8Utils::ToFString(context->GetIsolate(), value));
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsString();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct Converter<FArrayBuffer>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FArrayBuffer value)
|
||||
{
|
||||
return DataTransfer::NewArrayBuffer(context, value.Data, value.Length);
|
||||
}
|
||||
|
||||
static FArrayBuffer toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
FArrayBuffer Ret = {nullptr, 0};
|
||||
if (value->IsArrayBufferView())
|
||||
{
|
||||
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
|
||||
auto Ab = BuffView->Buffer();
|
||||
Ret.Data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset();
|
||||
Ret.Length = BuffView->ByteLength();
|
||||
}
|
||||
else if (value->IsArrayBuffer())
|
||||
{
|
||||
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
|
||||
size_t ByteLength;
|
||||
Ret.Data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab, ByteLength));
|
||||
Ret.Length = ByteLength;
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsArrayBuffer() || value->IsArrayBufferView();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<FArrayBufferValue>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FArrayBufferValue& value)
|
||||
{
|
||||
v8::Local<v8::ArrayBuffer> Ab = v8::ArrayBuffer::New(context->GetIsolate(), value.Data.Num());
|
||||
void* Buff = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab));
|
||||
::memcpy(Buff, value.Data.GetData(), value.Data.Num());
|
||||
return Ab;
|
||||
}
|
||||
|
||||
static FArrayBufferValue toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
FArrayBufferValue Ret;
|
||||
size_t Len = 0;
|
||||
void* Data = nullptr;
|
||||
if (value->IsArrayBufferView())
|
||||
{
|
||||
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
|
||||
auto Ab = BuffView->Buffer();
|
||||
Data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset();
|
||||
Len = BuffView->ByteLength();
|
||||
}
|
||||
else if (value->IsArrayBuffer())
|
||||
{
|
||||
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
|
||||
Data = DataTransfer::GetArrayBufferData(Ab, Len);
|
||||
}
|
||||
if (Len > 0 && Data)
|
||||
{
|
||||
Ret.Data.AddUninitialized(Len);
|
||||
::memcpy(Ret.Data.GetData(), Data, Len);
|
||||
}
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsArrayBuffer() || value->IsArrayBufferView();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Converter<T*, typename std::enable_if<std::is_convertible<T*, const UObject*>::value>::type>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T* value)
|
||||
{
|
||||
using TypeWithoutConst = typename std::remove_const<T>::type;
|
||||
return DataTransfer::FindOrAddObject<TypeWithoutConst>(context->GetIsolate(), context, (TypeWithoutConst*) (value));
|
||||
}
|
||||
|
||||
static T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
T* Ret = DataTransfer::GetPointerFast<T>(value.As<v8::Object>());
|
||||
return (!Ret || Ret == RELEASED_UOBJECT_MEMBER || !Ret->IsValidLowLevelFast() || UEObjectIsPendingKill(Ret)) ? nullptr
|
||||
: Ret;
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
if (value.As<v8::Object>()->IsNullOrUndefined())
|
||||
return true;
|
||||
return DataTransfer::IsInstanceOf(context->GetIsolate(), T::StaticClass(), value.As<v8::Object>());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Converter<T*, typename std::enable_if<!std::is_convertible<T*, const UObject*>::value &&
|
||||
std::is_convertible<T*, const UObjectBase*>::value>::type>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T* value)
|
||||
{
|
||||
return DataTransfer::FindOrAddObject<UObject>(context->GetIsolate(), context, static_cast<UObject*>(value));
|
||||
}
|
||||
|
||||
static T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
T* Ret = DataTransfer::GetPointerFast<T>(value.As<v8::Object>());
|
||||
return (!Ret || Ret == RELEASED_UOBJECT_MEMBER || !Ret->IsValidLowLevelFast()) ? nullptr : Ret;
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return DataTransfer::IsInstanceOf(context->GetIsolate(), UObject::StaticClass(), value.As<v8::Object>());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace v8_impl
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<FString>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("string");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<FName>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("string");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<const TCHAR*>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("string");
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef PUERTS_FTEXT_AS_OBJECT
|
||||
template <>
|
||||
struct ScriptTypeName<FText>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("string");
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<FArrayBuffer>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("ArrayBuffer");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<FArrayBufferValue>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("ArrayBuffer");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScriptTypeNameWithNamespace<T,
|
||||
typename std::enable_if<is_objecttype<typename std::remove_pointer<typename std::decay<T>::type>::type>::value>::type>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("cpp.") + ScriptTypeName<T>::value();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScriptTypeNameWithNamespace<T,
|
||||
typename std::enable_if<is_uetype<typename std::remove_pointer<typename std::decay<T>::type>::type>::value>::type>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("UE.") + ScriptTypeName<T>::value();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScriptTypeName<TSharedPtr<T>>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("UE.TSharedPtr<") + ScriptTypeNameWithNamespace<T>::value() + internal::Literal(">");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScriptTypeName<TArray<T>>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("UE.TArray<") + ScriptTypeNameWithNamespace<T>::value() + internal::Literal(">");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScriptTypeName<TSet<T>>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("UE.TSet<") + ScriptTypeNameWithNamespace<T>::value() + internal::Literal(">");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TKey, typename TValue>
|
||||
struct ScriptTypeName<TMap<TKey, TValue>>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("UE.TMap<") + ScriptTypeNameWithNamespace<TKey>::value() + internal::Literal(", ") +
|
||||
ScriptTypeNameWithNamespace<TValue>::value() + internal::Literal(">");
|
||||
}
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
template <typename T, typename = void>
|
||||
struct IsUStructHelper : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsUStructHelper<T, Void_t<decltype(&TScriptStructTraits<T>::Get)>> : std::true_type
|
||||
{
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
namespace v8_impl
|
||||
{
|
||||
template <typename T>
|
||||
struct Converter<T*,
|
||||
typename std::enable_if<!std::is_convertible<T*, const UObject*>::value && internal::IsUStructHelper<T>::value>::type>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T* value)
|
||||
{
|
||||
return DataTransfer::FindOrAddStruct<T>(context->GetIsolate(), context, (void*) value, true);
|
||||
}
|
||||
|
||||
static T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return DataTransfer::GetPointerFast<T>(value.As<v8::Object>());
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return DataTransfer::IsInstanceOf<T>(context->GetIsolate(), value.As<v8::Object>());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Converter<T, typename std::enable_if<internal::IsUStructHelper<T>::value>::type>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
|
||||
{
|
||||
return DataTransfer::FindOrAddStruct<T>(context->GetIsolate(), context, new T(value), false);
|
||||
}
|
||||
|
||||
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
T* ptr = DataTransfer::GetPointerFast<T>(value.As<v8::Object>());
|
||||
return ptr ? *ptr : T{};
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return DataTransfer::IsInstanceOf<T>(context->GetIsolate(), value.As<v8::Object>());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace v8_impl
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
* 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 <functional>
|
||||
#include "DataTransfer.h"
|
||||
#include "JSClassRegister.h"
|
||||
|
||||
#define __DefObjectType_v8_impl(CLS) \
|
||||
namespace PUERTS_NAMESPACE \
|
||||
{ \
|
||||
template <> \
|
||||
struct is_objecttype<CLS> : public std::true_type \
|
||||
{ \
|
||||
}; \
|
||||
}
|
||||
|
||||
#define __DefCDataPointerConverter_v8_impl(CLS) \
|
||||
namespace PUERTS_NAMESPACE \
|
||||
{ \
|
||||
namespace v8_impl \
|
||||
{ \
|
||||
template <> \
|
||||
struct Converter<CLS*> \
|
||||
{ \
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, CLS* value) \
|
||||
{ \
|
||||
return ::PUERTS_NAMESPACE::DataTransfer::FindOrAddCData( \
|
||||
context->GetIsolate(), context, DynamicTypeId<CLS>::get(value), value, true); \
|
||||
} \
|
||||
static CLS* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value) \
|
||||
{ \
|
||||
return ::PUERTS_NAMESPACE::DataTransfer::GetPointerFast<CLS>(value.As<v8::Object>()); \
|
||||
} \
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value) \
|
||||
{ \
|
||||
return ::PUERTS_NAMESPACE::DataTransfer::IsInstanceOf( \
|
||||
context->GetIsolate(), StaticTypeId<CLS>::get(), value.As<v8::Object>()); \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
namespace v8_impl
|
||||
{
|
||||
template <typename T, typename Enable = void>
|
||||
struct Converter;
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct CustomArgumentBufferType
|
||||
{
|
||||
static constexpr bool enable = false;
|
||||
};
|
||||
|
||||
struct API
|
||||
{
|
||||
typedef const v8::FunctionCallbackInfo<v8::Value>& CallbackInfoType;
|
||||
typedef v8::Local<v8::Context> ContextType;
|
||||
typedef v8::Local<v8::Value> ValueType;
|
||||
typedef v8::FunctionCallback FunctionCallbackType;
|
||||
typedef void* (*InitializeFuncType)(const v8::FunctionCallbackInfo<v8::Value>& Info);
|
||||
typedef void (*FinalizeFuncType)(void* Ptr, void* ClassData, void* EnvData);
|
||||
typedef JSFunctionInfo GeneralFunctionInfo;
|
||||
typedef JSPropertyInfo GeneralPropertyInfo;
|
||||
typedef NamedFunctionInfo GeneralFunctionReflectionInfo;
|
||||
typedef NamedPropertyInfo GeneralPropertyReflectionInfo;
|
||||
|
||||
V8_INLINE static int GetArgsLen(const v8::FunctionCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
return info.Length();
|
||||
}
|
||||
|
||||
V8_INLINE static v8::Local<v8::Value> GetArg(const v8::FunctionCallbackInfo<v8::Value>& info, int index)
|
||||
{
|
||||
return info[index];
|
||||
}
|
||||
|
||||
V8_INLINE static v8::Local<v8::Context> GetContext(const v8::FunctionCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
return info.GetIsolate()->GetCurrentContext();
|
||||
}
|
||||
V8_INLINE static v8::Local<v8::Object> GetThis(const v8::FunctionCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
return info.This();
|
||||
}
|
||||
|
||||
V8_INLINE static v8::Local<v8::Object> GetHolder(const v8::FunctionCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
return info.Holder();
|
||||
}
|
||||
|
||||
// use where GetSelfFromData is true
|
||||
V8_INLINE static void* GetFunctionData(const v8::FunctionCallbackInfo<v8::Value>& info)
|
||||
{
|
||||
return v8::Local<v8::External>::Cast(info.Data())->Value();
|
||||
}
|
||||
|
||||
V8_INLINE static void ThrowException(const v8::FunctionCallbackInfo<v8::Value>& info, const char* msg)
|
||||
{
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
isolate->ThrowException(
|
||||
v8::Exception::Error(v8::String::NewFromUtf8(isolate, msg, v8::NewStringType::kNormal).ToLocalChecked()));
|
||||
}
|
||||
|
||||
V8_INLINE static void SetReturn(const v8::FunctionCallbackInfo<v8::Value>& info, v8::Local<v8::Value> value)
|
||||
{
|
||||
info.GetReturnValue().Set(value);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
V8_INLINE static void LinkOuter(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
|
||||
{
|
||||
LinkOuterImpl(Context, Outer, Inner);
|
||||
}
|
||||
|
||||
V8_INLINE static void UpdateRefValue(v8::Local<v8::Context> context, v8::Local<v8::Value> holder, v8::Local<v8::Value> value)
|
||||
{
|
||||
if (holder->IsObject())
|
||||
{
|
||||
auto outer = holder->ToObject(context).ToLocalChecked();
|
||||
(void) (outer->Set(context, 0, value));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
V8_INLINE static T* FastGetNativeObjectPointer(v8::Local<v8::Context> context, v8::Local<v8::Object> Object)
|
||||
{
|
||||
return DataTransfer::GetPointerFast<T>(Object);
|
||||
}
|
||||
|
||||
V8_INLINE static v8::Local<v8::Value> GetUndefined(v8::Local<v8::Context> context)
|
||||
{
|
||||
return v8::Undefined(context->GetIsolate());
|
||||
}
|
||||
|
||||
V8_INLINE static bool IsNullOrUndefined(v8::Local<v8::Context> context, v8::Local<v8::Value> val)
|
||||
{
|
||||
return val->IsNullOrUndefined();
|
||||
}
|
||||
|
||||
template <typename T, typename CDB>
|
||||
static void Register(FinalizeFuncType Finalize, const CDB& Cdb)
|
||||
{
|
||||
const bool isUEType = is_uetype<T>::value;
|
||||
static std::vector<JSFunctionInfo> s_functions_{};
|
||||
static std::vector<JSFunctionInfo> s_methods_{};
|
||||
static std::vector<JSPropertyInfo> s_properties_{};
|
||||
static std::vector<JSPropertyInfo> s_variables_{};
|
||||
|
||||
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_{};
|
||||
|
||||
JSClassDefinition ClassDef = JSClassEmptyDefinition;
|
||||
|
||||
if (isUEType)
|
||||
{
|
||||
ClassDef.UETypeName = Cdb.className_;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClassDef.ScriptName = Cdb.className_;
|
||||
ClassDef.TypeId = StaticTypeId<T>::get();
|
||||
ClassDef.SuperTypeId = Cdb.superTypeId_;
|
||||
}
|
||||
|
||||
ClassDef.SetInitialize(Cdb.constructor_);
|
||||
ClassDef.Finalize = Finalize;
|
||||
|
||||
s_functions_ = std::move(Cdb.functions_);
|
||||
s_functions_.push_back(JSFunctionInfo());
|
||||
ClassDef.Functions = s_functions_.data();
|
||||
|
||||
s_methods_ = std::move(Cdb.methods_);
|
||||
s_methods_.push_back(JSFunctionInfo());
|
||||
ClassDef.Methods = s_methods_.data();
|
||||
|
||||
s_properties_ = std::move(Cdb.properties_);
|
||||
s_properties_.push_back(JSPropertyInfo());
|
||||
ClassDef.Properties = s_properties_.data();
|
||||
|
||||
s_variables_ = std::move(Cdb.variables_);
|
||||
s_variables_.push_back(JSPropertyInfo());
|
||||
ClassDef.Variables = s_variables_.data();
|
||||
|
||||
s_constructorInfos_ = std::move(Cdb.constructorInfos_);
|
||||
s_constructorInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
|
||||
ClassDef.ConstructorInfos = s_constructorInfos_.data();
|
||||
|
||||
s_methodInfos_ = std::move(Cdb.methodInfos_);
|
||||
s_methodInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
|
||||
ClassDef.MethodInfos = s_methodInfos_.data();
|
||||
|
||||
s_functionInfos_ = std::move(Cdb.functionInfos_);
|
||||
s_functionInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
|
||||
ClassDef.FunctionInfos = s_functionInfos_.data();
|
||||
|
||||
s_propertyInfos_ = std::move(Cdb.propertyInfos_);
|
||||
s_propertyInfos_.push_back(NamedPropertyInfo{nullptr, nullptr});
|
||||
ClassDef.PropertyInfos = s_propertyInfos_.data();
|
||||
|
||||
s_variableInfos_ = std::move(Cdb.variableInfos_);
|
||||
s_variableInfos_.push_back(NamedPropertyInfo{nullptr, nullptr});
|
||||
ClassDef.VariableInfos = s_variableInfos_.data();
|
||||
|
||||
RegisterJSClass(ClassDef);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using Converter = Converter<T>;
|
||||
|
||||
template <typename T>
|
||||
using CustomArgumentBufferType = CustomArgumentBufferType<T>;
|
||||
};
|
||||
|
||||
class StringHolder
|
||||
{
|
||||
public:
|
||||
StringHolder(v8::Local<v8::Context> context, const v8::Local<v8::Value> value)
|
||||
{
|
||||
needFree = false;
|
||||
if (value->IsArrayBufferView())
|
||||
{
|
||||
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
|
||||
auto Ab = BuffView->Buffer();
|
||||
data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset();
|
||||
}
|
||||
else if (value->IsArrayBuffer())
|
||||
{
|
||||
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
|
||||
data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value.IsEmpty())
|
||||
return;
|
||||
const auto isolate = context->GetIsolate();
|
||||
v8::TryCatch try_catch(isolate);
|
||||
v8::Local<v8::String> str;
|
||||
if (!value->ToString(context).ToLocal(&str))
|
||||
return;
|
||||
const int length = str->Utf8Length(isolate);
|
||||
data = new char[length + 1];
|
||||
str->WriteUtf8(isolate, data);
|
||||
needFree = true;
|
||||
}
|
||||
}
|
||||
|
||||
~StringHolder()
|
||||
{
|
||||
if (needFree && data)
|
||||
{
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
|
||||
const char* Data() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
// Disallow copying and assigning.
|
||||
StringHolder(const StringHolder&) = delete;
|
||||
void operator=(const StringHolder&) = delete;
|
||||
|
||||
private:
|
||||
char* data;
|
||||
|
||||
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 v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
|
||||
{
|
||||
return v8::BigInt::New(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsBigInt() ? static_cast<T>(value->ToBigInt(context).ToLocalChecked()->Int64Value()) : 0;
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsBigInt();
|
||||
}
|
||||
};
|
||||
|
||||
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 v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
|
||||
{
|
||||
return v8::BigInt::NewFromUnsigned(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsBigInt() ? static_cast<T>(value->ToBigInt(context).ToLocalChecked()->Uint64Value()) : 0;
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsBigInt();
|
||||
}
|
||||
};
|
||||
|
||||
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 v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
|
||||
{
|
||||
return v8::Integer::New(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return static_cast<T>(value->Int32Value(context).ToChecked());
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsInt32();
|
||||
}
|
||||
};
|
||||
|
||||
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 v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
|
||||
{
|
||||
return v8::Integer::NewFromUnsigned(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return static_cast<T>(value->Uint32Value(context).ToChecked());
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsUint32();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Converter<T, typename std::enable_if<std::is_enum<T>::value>::type>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
|
||||
{
|
||||
return v8::Integer::New(context->GetIsolate(), static_cast<int>(value));
|
||||
}
|
||||
|
||||
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return static_cast<T>(value->Int32Value(context).ToChecked());
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsInt32();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Converter<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
|
||||
{
|
||||
return v8::Number::New(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return static_cast<T>(value->NumberValue(context).ToChecked());
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsNumber();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<std::string>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, std::string value)
|
||||
{
|
||||
return v8::String::NewFromUtf8(context->GetIsolate(), value.c_str(), v8::NewStringType::kNormal).ToLocalChecked();
|
||||
}
|
||||
|
||||
static std::string toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return *v8::String::Utf8Value(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsString();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<const char*>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const char* value)
|
||||
{
|
||||
return v8::String::NewFromUtf8(context->GetIsolate(), value, v8::NewStringType::kNormal).ToLocalChecked();
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsString();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<void*>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, void* value)
|
||||
{
|
||||
return DataTransfer::NewArrayBuffer(context, value, 0);
|
||||
}
|
||||
|
||||
static void* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
if (value->IsArrayBufferView())
|
||||
{
|
||||
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
|
||||
auto Ab = BuffView->Buffer();
|
||||
return static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset();
|
||||
}
|
||||
if (value->IsArrayBuffer())
|
||||
{
|
||||
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
|
||||
return DataTransfer::GetArrayBufferData(Ab);
|
||||
}
|
||||
if (value->IsObject())
|
||||
{
|
||||
return DataTransfer::GetPointerFast<void>(value.As<v8::Object>());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsArrayBuffer() || value->IsArrayBufferView();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<bool>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, bool value)
|
||||
{
|
||||
return v8::Boolean::New(context->GetIsolate(), value);
|
||||
}
|
||||
|
||||
static bool toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->BooleanValue(context->GetIsolate());
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsBoolean();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Converter<std::reference_wrapper<T>, typename std::enable_if<!is_objecttype<T>::value && !is_uetype<T>::value>::type>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const T& value)
|
||||
{
|
||||
auto result = v8::Object::New(context->GetIsolate());
|
||||
auto _unused = result->Set(context, 0, Converter<T>::toScript(context, value));
|
||||
return result;
|
||||
}
|
||||
|
||||
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
if (value->IsObject())
|
||||
{
|
||||
auto outer = value->ToObject(context).ToLocalChecked();
|
||||
auto realvalue = outer->Get(context, 0).ToLocalChecked();
|
||||
return Converter<T>::toCpp(context, realvalue);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsObject(); // do not checked inner
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Converter<std::reference_wrapper<T>, typename std::enable_if<is_objecttype<T>::value || is_uetype<T>::value>::type>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const T& value)
|
||||
{
|
||||
auto result = v8::Object::New(context->GetIsolate());
|
||||
auto _unused = result->Set(context, 0, Converter<T>::toScript(context, value));
|
||||
return result;
|
||||
}
|
||||
|
||||
static T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
if (!value.IsEmpty() && value->IsObject())
|
||||
{
|
||||
auto outer = value->ToObject(context).ToLocalChecked();
|
||||
auto realvalue = outer->Get(context, 0).ToLocalChecked();
|
||||
return Converter<typename std::decay<T>::type*>::toCpp(context, realvalue);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsObject(); // 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 v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
|
||||
{
|
||||
return DataTransfer::NewArrayBuffer(context, value, 0);
|
||||
}
|
||||
|
||||
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
if (value->IsArrayBufferView())
|
||||
{
|
||||
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
|
||||
auto Ab = BuffView->Buffer();
|
||||
return reinterpret_cast<T>(static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset());
|
||||
}
|
||||
if (value->IsArrayBuffer())
|
||||
{
|
||||
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
|
||||
return static_cast<T>(DataTransfer::GetArrayBufferData(Ab));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsArrayBuffer() || value->IsArrayBufferView();
|
||||
}
|
||||
};
|
||||
|
||||
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 v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value[Size])
|
||||
{
|
||||
return DataTransfer::NewArrayBuffer(context, &(value[0]), sizeof(T) * Size);
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
if (value->IsArrayBufferView())
|
||||
{
|
||||
v8::Local<v8::ArrayBufferView> buffView = value.As<v8::ArrayBufferView>();
|
||||
return buffView->ByteLength() >= sizeof(T) * Size;
|
||||
}
|
||||
if (value->IsArrayBuffer())
|
||||
{
|
||||
auto ab = v8::Local<v8::ArrayBuffer>::Cast(value);
|
||||
size_t byteLength;
|
||||
(void) (DataTransfer::GetArrayBufferData(ab, byteLength));
|
||||
return byteLength >= sizeof(T) * Size;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
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 v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
|
||||
{
|
||||
return DataTransfer::FindOrAddCData(context->GetIsolate(), context, DynamicTypeId<T>::get(&value), new T(value), false);
|
||||
}
|
||||
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
T* ptr = DataTransfer::GetPointerFast<T>(value.As<v8::Object>());
|
||||
return ptr ? *ptr : T{};
|
||||
}
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return DataTransfer::IsInstanceOf(context->GetIsolate(), StaticTypeId<T>::get(), value.As<v8::Object>());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Converter<const T*,
|
||||
typename std::enable_if<(is_objecttype<T>::value || std::is_same<T, void>::value || is_script_type<T>::value) &&
|
||||
!is_uetype<T>::value && !std::is_same<T, char>::value>::type>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const T* value)
|
||||
{
|
||||
return Converter<T*>::toScript(context, const_cast<T*>(value));
|
||||
}
|
||||
static const T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return Converter<T*>::toCpp(context, value);
|
||||
}
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return Converter<T*>::accept(context, value);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace v8_impl
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#pragma warning(push, 0)
|
||||
#include <v8-fast-api-calls.h>
|
||||
#pragma warning(pop)
|
||||
#include "DataTransfer.h"
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
template <typename T, typename Enable = void>
|
||||
struct FastCallArgument
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FastCallArgument<T, typename std::enable_if<std::is_pointer<T>::value && !std::is_same<T, const char*>::value &&
|
||||
!std::is_enum<typename std::remove_pointer<T>::type>::value &&
|
||||
!std::is_integral<typename std::remove_pointer<T>::type>::value &&
|
||||
!std::is_floating_point<typename std::remove_pointer<T>::type>::value>::type>
|
||||
{
|
||||
using DeclType = v8::Local<v8::Value>;
|
||||
|
||||
static T Get(v8::Local<v8::Value> v)
|
||||
{
|
||||
if (V8_LIKELY(v->IsObject()))
|
||||
{
|
||||
// return static_cast<T>(v.As<v8::Object>()->GetAlignedPointerFromInternalField(1));
|
||||
return static_cast<T>(DataTransfer::GetPointerFast<void>(v.As<v8::Object>()));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct FastCallArgument<std::string*>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FastCallArgument<T, typename std::enable_if<std::is_enum<T>::value>::type>
|
||||
{
|
||||
using DeclType = int;
|
||||
|
||||
static T Get(int i)
|
||||
{
|
||||
return static_cast<T>(i);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FastCallArgument<T, typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value>::type>
|
||||
{
|
||||
using DeclType = typename std::decay<T>::type;
|
||||
|
||||
static T Get(typename std::decay<T>::type i)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct FastCallArgument<bool>
|
||||
{
|
||||
using DeclType = bool;
|
||||
|
||||
static bool Get(bool i)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
namespace fastcallutil
|
||||
{
|
||||
template <bool _First_value, class _First, class... _Rest>
|
||||
struct _Conjunction
|
||||
{ // handle false trait or last trait
|
||||
using type = _First;
|
||||
};
|
||||
|
||||
template <class _True, class _Next, class... _Rest>
|
||||
struct _Conjunction<true, _True, _Next, _Rest...>
|
||||
{ // the first trait is true, try the next one
|
||||
using type = typename _Conjunction<_Next::value, _Next, _Rest...>::type;
|
||||
};
|
||||
|
||||
template <class... _Traits>
|
||||
struct Conjunction : std::true_type
|
||||
{
|
||||
}; // If _Traits is empty, true_type
|
||||
|
||||
template <class _First, class... _Rest>
|
||||
struct Conjunction<_First, _Rest...> : _Conjunction<_First::value, _First, _Rest...>::type
|
||||
{
|
||||
// the first false trait in _Traits, or the last trait if none are false
|
||||
};
|
||||
|
||||
template <class...>
|
||||
using Void_t = void;
|
||||
} // namespace fastcallutil
|
||||
} // namespace internal
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct IsArgSupportedHelper : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsArgSupportedHelper<T, internal::fastcallutil::Void_t<decltype(&FastCallArgument<T>::Get)>> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct IsArgsSupportedHelper : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
struct IsArgsSupportedHelper<std::tuple<Args...>,
|
||||
typename std::enable_if<internal::fastcallutil::Conjunction<IsArgSupportedHelper<Args>...>::value>::type> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct IsReturnSupportedHelper : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsReturnSupportedHelper<T,
|
||||
typename std::enable_if<IsArgSupportedHelper<T>::value && !std::is_pointer<T>::value && !std::is_integral<T>::value>::type>
|
||||
: std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsReturnSupportedHelper<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) < 8>::type> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IsReturnSupportedHelper<void> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, T, typename Enable = void>
|
||||
struct V8FastCall
|
||||
{
|
||||
static const v8::CFunction* info()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Ret, typename... Args, Ret (*func)(Args...)>
|
||||
struct V8FastCall<Ret (*)(Args...), func,
|
||||
typename std::enable_if<IsReturnSupportedHelper<Ret>::value && IsArgsSupportedHelper<std::tuple<Args...>>::value &&
|
||||
(sizeof...(Args) > 0)>::type>
|
||||
{
|
||||
static Ret Wrap(v8::Local<v8::Object> receiver_obj, typename FastCallArgument<Args>::DeclType... args)
|
||||
{
|
||||
return func(FastCallArgument<Args>::Get(args)...);
|
||||
}
|
||||
|
||||
static const v8::CFunction* info()
|
||||
{
|
||||
static v8::CFunction _info = v8::CFunction::Make(Wrap);
|
||||
return &_info;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Inc, typename Ret, typename... Args, Ret (Inc::*func)(Args...)>
|
||||
struct V8FastCall<Ret (Inc::*)(Args...), func,
|
||||
typename std::enable_if<IsReturnSupportedHelper<Ret>::value && IsArgsSupportedHelper<std::tuple<Args...>>::value>::type>
|
||||
{
|
||||
static Ret Wrap(v8::Local<v8::Object> receiver_obj, typename FastCallArgument<Args>::DeclType... args)
|
||||
{
|
||||
auto self = FastCallArgument<Inc*>::Get(receiver_obj);
|
||||
return (self->*func)(FastCallArgument<Args>::Get(args)...);
|
||||
}
|
||||
|
||||
static const v8::CFunction* info()
|
||||
{
|
||||
static v8::CFunction _info = v8::CFunction::Make(Wrap);
|
||||
return &_info;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Inc, typename Ret, typename... Args, Ret (Inc::*func)(Args...) const>
|
||||
struct V8FastCall<Ret (Inc::*)(Args...) const, func,
|
||||
typename std::enable_if<IsReturnSupportedHelper<Ret>::value && IsArgsSupportedHelper<std::tuple<Args...>>::value>::type>
|
||||
{
|
||||
static Ret Wrap(v8::Local<v8::Object> receiver_obj, typename FastCallArgument<Args>::DeclType... args)
|
||||
{
|
||||
auto self = FastCallArgument<Inc*>::Get(receiver_obj);
|
||||
return (self->*func)(FastCallArgument<Args>::Get(args)...);
|
||||
}
|
||||
|
||||
static const v8::CFunction* info()
|
||||
{
|
||||
static v8::CFunction _info = v8::CFunction::Make(Wrap);
|
||||
return &_info;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* 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 "Binding.hpp"
|
||||
#include <memory>
|
||||
|
||||
#ifdef USING_IN_UNREAL_ENGINE
|
||||
#include "JSLogger.h"
|
||||
#include "V8Utils.h"
|
||||
#else
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
namespace v8_impl
|
||||
{
|
||||
static inline void REPORT_EXCEPTION(v8::Isolate* Isolate, v8::TryCatch* TC)
|
||||
{
|
||||
#ifdef USING_IN_UNREAL_ENGINE
|
||||
UE_LOG(Puerts, Error, TEXT("call function throw: %s"), *FV8Utils::TryCatchToString(Isolate, TC));
|
||||
#else
|
||||
std::cout << "call function throw: " << *v8::String::Utf8Value(Isolate, TC->Exception()) << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
Object()
|
||||
{
|
||||
}
|
||||
|
||||
Object(v8::Local<v8::Context> context, v8::Local<v8::Value> object)
|
||||
{
|
||||
Isolate = context->GetIsolate();
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
GContext.Reset(Isolate, context);
|
||||
GObject.Reset(Isolate, object.As<v8::Object>());
|
||||
JsEnvLifeCycleTracker = DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
|
||||
}
|
||||
|
||||
Object(const Object& InOther)
|
||||
{
|
||||
if (InOther.JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
JsEnvLifeCycleTracker = InOther.JsEnvLifeCycleTracker;
|
||||
return;
|
||||
}
|
||||
Isolate = InOther.Isolate;
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
GContext.Reset(Isolate, InOther.GContext.Get(Isolate));
|
||||
GObject.Reset(Isolate, InOther.GObject.Get(Isolate));
|
||||
JsEnvLifeCycleTracker = DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
|
||||
}
|
||||
|
||||
Object& operator=(const Object& InOther)
|
||||
{
|
||||
if (InOther.JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
JsEnvLifeCycleTracker = InOther.JsEnvLifeCycleTracker;
|
||||
return *this;
|
||||
}
|
||||
Isolate = InOther.Isolate;
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
GContext.Reset(Isolate, InOther.GContext.Get(Isolate));
|
||||
GObject.Reset(Isolate, InOther.GObject.Get(Isolate));
|
||||
JsEnvLifeCycleTracker = DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Object()
|
||||
{
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
if (JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
#if V8_MAJOR_VERSION < 11
|
||||
GObject.Empty();
|
||||
GContext.Empty();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
GObject.Reset();
|
||||
GContext.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Get(const char* key) const
|
||||
{
|
||||
if (JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
auto Context = GContext.Get(Isolate);
|
||||
v8::Context::Scope ContextScope(Context);
|
||||
auto Object = GObject.Get(Isolate);
|
||||
|
||||
auto MaybeValue = Object->Get(Context, v8_impl::Converter<const char*>::toScript(Context, key));
|
||||
v8::Local<v8::Value> Val;
|
||||
if (MaybeValue.ToLocal(&Val))
|
||||
{
|
||||
return v8_impl::Converter<T>::toCpp(Context, Val);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Set(const char* key, T val) const
|
||||
{
|
||||
if (JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
auto Context = GContext.Get(Isolate);
|
||||
v8::Context::Scope ContextScope(Context);
|
||||
auto Object = GObject.Get(Isolate);
|
||||
|
||||
auto _UnUsed = Object->Set(
|
||||
Context, v8_impl::Converter<const char*>::toScript(Context, key), v8_impl::Converter<T>::toScript(Context, val));
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
if (JsEnvLifeCycleTracker.expired() || !Isolate || GContext.IsEmpty() || GObject.IsEmpty())
|
||||
return false;
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
auto Context = GContext.Get(Isolate);
|
||||
v8::Context::Scope ContextScope(Context);
|
||||
auto Object = GObject.Get(Isolate);
|
||||
return !Object.IsEmpty() && Object->IsObject();
|
||||
}
|
||||
|
||||
// for performance considerations, a native can only hold one JavaScript object at a time (the last setting takes effect if set
|
||||
// multiple times). If there is a need to hold more than one JavaScript object, it is recommended to first hold a JavaScript
|
||||
// array and then add objects to the array.
|
||||
template <typename T>
|
||||
void SetWeakAndOwnBy(const T* Owner)
|
||||
{
|
||||
if (!Owner)
|
||||
return;
|
||||
if (JsEnvLifeCycleTracker.expired() || !Isolate || GContext.IsEmpty() || GObject.IsEmpty())
|
||||
return;
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
auto Context = GContext.Get(Isolate);
|
||||
v8::Context::Scope ContextScope(Context);
|
||||
|
||||
auto Val = DataTransfer::FindOrAddCData(Isolate, Context, StaticTypeId<T>::get(), Owner, true);
|
||||
if (Val->IsObject())
|
||||
{
|
||||
auto JsObject = Val.template As<v8::Object>();
|
||||
#if V8_MAJOR_VERSION < 8
|
||||
JsObject->Set(Context, v8::String::NewFromUtf8(Isolate, "_p_i_only_one_child").ToLocalChecked(), GObject.Get(Isolate))
|
||||
.Check();
|
||||
#else
|
||||
JsObject->Set(Context, v8::String::NewFromUtf8Literal(Isolate, "_p_i_only_one_child"), GObject.Get(Isolate)).Check();
|
||||
#endif
|
||||
GObject.SetWeak();
|
||||
}
|
||||
}
|
||||
|
||||
v8::Isolate* Isolate;
|
||||
#if V8_MAJOR_VERSION >= 11
|
||||
v8::Persistent<v8::Context> GContext;
|
||||
v8::Persistent<v8::Object> GObject;
|
||||
#else
|
||||
v8::Global<v8::Context> GContext;
|
||||
v8::Global<v8::Object> GObject;
|
||||
#endif
|
||||
|
||||
std::weak_ptr<int> JsEnvLifeCycleTracker;
|
||||
|
||||
friend struct PUERTS_NAMESPACE::v8_impl::Converter<Object>;
|
||||
};
|
||||
|
||||
class Function : public Object
|
||||
{
|
||||
public:
|
||||
Function()
|
||||
{
|
||||
}
|
||||
|
||||
Function(v8::Local<v8::Context> context, v8::Local<v8::Value> object) : Object(context, object)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void Action(Args... cppArgs) const
|
||||
{
|
||||
if (JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
auto Context = GContext.Get(Isolate);
|
||||
v8::Context::Scope ContextScope(Context);
|
||||
|
||||
auto Object = GObject.Get(Isolate);
|
||||
|
||||
v8::TryCatch TryCatch(Isolate);
|
||||
|
||||
auto _UnUsed = InvokeHelper(Context, Object, cppArgs...);
|
||||
|
||||
if (TryCatch.HasCaught())
|
||||
{
|
||||
REPORT_EXCEPTION(Isolate, &TryCatch);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Ret, typename... Args>
|
||||
Ret Func(Args... cppArgs) const
|
||||
{
|
||||
if (JsEnvLifeCycleTracker.expired())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
auto Context = GContext.Get(Isolate);
|
||||
v8::Context::Scope ContextScope(Context);
|
||||
|
||||
auto Object = GObject.Get(Isolate);
|
||||
|
||||
v8::TryCatch TryCatch(Isolate);
|
||||
|
||||
auto MaybeRet = InvokeHelper(Context, Object, cppArgs...);
|
||||
|
||||
if (TryCatch.HasCaught())
|
||||
{
|
||||
REPORT_EXCEPTION(Isolate, &TryCatch);
|
||||
}
|
||||
|
||||
if (!MaybeRet.IsEmpty())
|
||||
{
|
||||
return v8_impl::Converter<Ret>::toCpp(Context, MaybeRet.ToLocalChecked());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
if (JsEnvLifeCycleTracker.expired() || !Isolate || GContext.IsEmpty() || GObject.IsEmpty())
|
||||
return false;
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(Isolate);
|
||||
#endif
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
auto Context = GContext.Get(Isolate);
|
||||
v8::Context::Scope ContextScope(Context);
|
||||
auto Object = GObject.Get(Isolate);
|
||||
return !Object.IsEmpty() && Object->IsFunction();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename... Args>
|
||||
auto InvokeHelper(v8::Local<v8::Context>& Context, v8::Local<v8::Object>& Object, Args... CppArgs) const
|
||||
{
|
||||
v8::Local<v8::Value> Argv[sizeof...(Args)]{v8_impl::Converter<Args>::toScript(Context, CppArgs)...};
|
||||
return Object.As<v8::Function>()->Call(Context, v8::Undefined(Isolate), sizeof...(Args), Argv);
|
||||
}
|
||||
|
||||
auto InvokeHelper(v8::Local<v8::Context>& Context, v8::Local<v8::Object>& Object) const
|
||||
{
|
||||
return Object.As<v8::Function>()->Call(Context, v8::Undefined(Isolate), 0, nullptr);
|
||||
}
|
||||
|
||||
friend struct PUERTS_NAMESPACE::v8_impl::Converter<Function>;
|
||||
};
|
||||
|
||||
} // namespace v8_impl
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<v8_impl::Object>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("object");
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScriptTypeName<v8_impl::Function>
|
||||
{
|
||||
static constexpr auto value()
|
||||
{
|
||||
return internal::Literal("()=>void");
|
||||
}
|
||||
};
|
||||
|
||||
namespace v8_impl
|
||||
{
|
||||
template <>
|
||||
struct Converter<Object>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, Object value)
|
||||
{
|
||||
return value.GObject.Get(context->GetIsolate());
|
||||
}
|
||||
|
||||
static Object toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return Object(context, value.As<v8::Object>());
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsObject();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<Function>
|
||||
{
|
||||
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, Function value)
|
||||
{
|
||||
return value.GObject.Get(context->GetIsolate());
|
||||
}
|
||||
|
||||
static Function toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return Function(context, value.As<v8::Object>());
|
||||
}
|
||||
|
||||
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
|
||||
{
|
||||
return value->IsFunction();
|
||||
}
|
||||
};
|
||||
|
||||
#include "StdFunctionConverter.hpp"
|
||||
} // namespace v8_impl
|
||||
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* 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 <vector>
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CoreUObject.h"
|
||||
#include "NamespaceDef.h"
|
||||
#include "DataTransfer.h"
|
||||
#include "UECompatible.h"
|
||||
|
||||
namespace PUERTS_NAMESPACE
|
||||
{
|
||||
enum ArgType
|
||||
{
|
||||
EArgInt32,
|
||||
EArgNumber,
|
||||
EArgString,
|
||||
EArgExternal,
|
||||
EArgFunction,
|
||||
EArgObject
|
||||
};
|
||||
|
||||
class JSENV_API FV8Utils
|
||||
{
|
||||
public:
|
||||
FORCEINLINE static void ThrowException(v8::Isolate* Isolate, const FString& Message)
|
||||
{
|
||||
ThrowException(Isolate, TCHAR_TO_ANSI(*Message));
|
||||
}
|
||||
|
||||
FORCEINLINE static void ThrowException(v8::Isolate* Isolate, const char* Message)
|
||||
{
|
||||
auto ExceptionStr = v8::String::NewFromUtf8(Isolate, Message, v8::NewStringType::kNormal).ToLocalChecked();
|
||||
Isolate->ThrowException(v8::Exception::Error(ExceptionStr));
|
||||
}
|
||||
|
||||
FORCEINLINE static void* GetPointer(v8::Local<v8::Context>& Context, v8::Local<v8::Value> Value, int Index = 0)
|
||||
{
|
||||
if (Value.IsEmpty() || !Value->IsObject() || Value->IsUndefined() || Value->IsNull())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
auto Object = Value->ToObject(Context).ToLocalChecked();
|
||||
return GetPointerFast<void>(Object, Index);
|
||||
}
|
||||
|
||||
FORCEINLINE static void* GetPointer(v8::Local<v8::Object> Object, int Index = 0)
|
||||
{
|
||||
if (Object.IsEmpty() || Object->IsUndefined() || Object->IsNull())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return GetPointerFast<void>(Object, Index);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCEINLINE static T* GetPointerFast(v8::Local<v8::Object> Object, int Index = 0)
|
||||
{
|
||||
return DataTransfer::GetPointerFast<T>(Object, Index);
|
||||
}
|
||||
|
||||
FORCEINLINE static UObject* GetUObject(v8::Local<v8::Context>& Context, v8::Local<v8::Value> Value, int Index = 0)
|
||||
{
|
||||
auto UEObject = reinterpret_cast<UObject*>(GetPointer(Context, Value, Index));
|
||||
return (!UEObject || (UEObject != RELEASED_UOBJECT && UEObject->IsValidLowLevelFast() && !UEObjectIsPendingKill(UEObject)))
|
||||
? UEObject
|
||||
: RELEASED_UOBJECT;
|
||||
}
|
||||
|
||||
FORCEINLINE static UObject* GetUObject(v8::Local<v8::Object> Object, int Index = 0)
|
||||
{
|
||||
auto UEObject = reinterpret_cast<UObject*>(GetPointer(Object, Index));
|
||||
return (!UEObject || (UEObject != RELEASED_UOBJECT && UEObject->IsValidLowLevelFast() && !UEObjectIsPendingKill(UEObject)))
|
||||
? UEObject
|
||||
: RELEASED_UOBJECT;
|
||||
}
|
||||
|
||||
FORCEINLINE static bool IsReleasedPtr(void* Ptr)
|
||||
{
|
||||
return RELEASED_UOBJECT_MEMBER == Ptr;
|
||||
}
|
||||
|
||||
FORCEINLINE static v8::Local<v8::String> InternalString(v8::Isolate* Isolate, const FString& String)
|
||||
{
|
||||
return ToV8String(Isolate, String);
|
||||
}
|
||||
|
||||
FORCEINLINE static v8::Local<v8::String> InternalString(v8::Isolate* Isolate, const char* String)
|
||||
{
|
||||
return v8::String::NewFromUtf8(Isolate, String, v8::NewStringType::kNormal).ToLocalChecked();
|
||||
}
|
||||
|
||||
static FString ToFString(v8::Isolate* Isolate, v8::Local<v8::Value> Value);
|
||||
|
||||
FORCEINLINE static FName ToFName(v8::Isolate* Isolate, v8::Local<v8::Value> Value)
|
||||
{
|
||||
return UTF8_TO_TCHAR(*(v8::String::Utf8Value(Isolate, Value)));
|
||||
}
|
||||
|
||||
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const FString& String)
|
||||
{
|
||||
// return ToV8String(Isolate, TCHAR_TO_UTF8(*String));
|
||||
return ToV8String(Isolate, *String);
|
||||
}
|
||||
|
||||
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const FName& String)
|
||||
{
|
||||
const FNameEntry* Entry = String.GetComparisonNameEntry();
|
||||
FString Out;
|
||||
if (String.GetNumber() == NAME_NO_NUMBER_INTERNAL)
|
||||
{
|
||||
Out.Empty(Entry->GetNameLength());
|
||||
Entry->AppendNameToString(Out);
|
||||
}
|
||||
else
|
||||
{
|
||||
Out.Empty(Entry->GetNameLength() + 6);
|
||||
Entry->AppendNameToString(Out);
|
||||
|
||||
Out += TEXT('_');
|
||||
Out.AppendInt(NAME_INTERNAL_TO_EXTERNAL(String.GetNumber()));
|
||||
}
|
||||
|
||||
return ToV8String(Isolate, Out);
|
||||
}
|
||||
|
||||
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const FText& String)
|
||||
{
|
||||
return ToV8String(Isolate, String.ToString());
|
||||
}
|
||||
|
||||
static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const TCHAR* String);
|
||||
|
||||
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const char* String)
|
||||
{
|
||||
return v8::String::NewFromUtf8(Isolate, String, v8::NewStringType::kNormal).ToLocalChecked();
|
||||
}
|
||||
|
||||
static v8::Local<v8::String> ToV8StringFromFileContent(v8::Isolate* Isolate, const TArray<uint8>& FileContent)
|
||||
{
|
||||
const uint8* Buffer = FileContent.GetData();
|
||||
auto Size = FileContent.Num();
|
||||
|
||||
if (Size >= 2 && !(Size & 1) && ((Buffer[0] == 0xff && Buffer[1] == 0xfe) || (Buffer[0] == 0xfe && Buffer[1] == 0xff)))
|
||||
{
|
||||
FString Content;
|
||||
FFileHelper::BufferToString(Content, Buffer, Size);
|
||||
return ToV8String(Isolate, Content);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Size >= 3 && Buffer[0] == 0xef && Buffer[1] == 0xbb && Buffer[2] == 0xbf)
|
||||
{
|
||||
// Skip over UTF-8 BOM if there is one
|
||||
Buffer += 3;
|
||||
Size -= 3;
|
||||
}
|
||||
return v8::String::NewFromUtf8(Isolate, (const char*) Buffer, v8::NewStringType::kNormal, Size).ToLocalChecked();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCEINLINE static T* IsolateData(v8::Isolate* Isolate)
|
||||
{
|
||||
return DataTransfer::IsolateData<T>(Isolate);
|
||||
}
|
||||
|
||||
FORCEINLINE static bool CheckArgumentLength(const v8::FunctionCallbackInfo<v8::Value>& Info, int32 Length)
|
||||
{
|
||||
if (Info.Length() < Length)
|
||||
{
|
||||
ThrowException(Info.GetIsolate(),
|
||||
FString::Printf(TEXT("Bad parameters, the function expect %d, but %d provided."), Length, Info.Length()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
FORCEINLINE static FString TryCatchToString(v8::Isolate* Isolate, v8::TryCatch* TryCatch)
|
||||
{
|
||||
v8::Isolate::Scope IsolateScope(Isolate);
|
||||
v8::HandleScope HandleScope(Isolate);
|
||||
v8::String::Utf8Value Exception(Isolate, TryCatch->Exception());
|
||||
FString ExceptionStr(UTF8_TO_TCHAR(*Exception));
|
||||
v8::Local<v8::Message> Message = TryCatch->Message();
|
||||
if (Message.IsEmpty())
|
||||
{
|
||||
// 如果没有提供更详细的信息,直接输出Exception
|
||||
return ExceptionStr;
|
||||
}
|
||||
else
|
||||
{
|
||||
v8::Local<v8::Context> Context(Isolate->GetCurrentContext());
|
||||
|
||||
// 输出 (filename):(line number): (message).
|
||||
v8::String::Utf8Value FileName(Isolate, Message->GetScriptResourceName());
|
||||
int LineNum = Message->GetLineNumber(Context).FromJust();
|
||||
FString FileNameStr(*FileName);
|
||||
FString LineNumStr = FString::FromInt(LineNum);
|
||||
FString FileInfoStr;
|
||||
FileInfoStr.Append(FileNameStr).Append(":").Append(LineNumStr).Append(": ").Append(ExceptionStr);
|
||||
|
||||
FString FinalReport;
|
||||
FinalReport.Append(FileInfoStr).Append("\n");
|
||||
|
||||
// 输出调用栈信息
|
||||
v8::Local<v8::Value> StackTrace;
|
||||
if (TryCatch->StackTrace(Context).ToLocal(&StackTrace))
|
||||
{
|
||||
v8::String::Utf8Value StackTraceVal(Isolate, StackTrace);
|
||||
FString StackTraceStr(*StackTraceVal);
|
||||
FinalReport.Append("\n").Append(StackTraceStr);
|
||||
}
|
||||
return FinalReport;
|
||||
}
|
||||
}
|
||||
|
||||
FORCEINLINE static bool CheckArgument(const v8::FunctionCallbackInfo<v8::Value>& Info, const std::vector<ArgType>& TypesExpect)
|
||||
{
|
||||
if (Info.Length() < TypesExpect.size())
|
||||
{
|
||||
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters, the function expect %d, but %d provided."),
|
||||
TypesExpect.size(), Info.Length()));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < TypesExpect.size(); ++i)
|
||||
{
|
||||
switch (TypesExpect[i])
|
||||
{
|
||||
case EArgInt32:
|
||||
if (!Info[i]->IsInt32())
|
||||
{
|
||||
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a int32."), i));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
case EArgNumber:
|
||||
if (!Info[i]->IsNumber())
|
||||
{
|
||||
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a int32."), i));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
case EArgString:
|
||||
if (!Info[i]->IsString())
|
||||
{
|
||||
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a string."), i));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
case EArgExternal:
|
||||
if (!Info[i]->IsExternal())
|
||||
{
|
||||
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect an external."), i));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
case EArgFunction:
|
||||
if (!Info[i]->IsFunction())
|
||||
{
|
||||
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a function."), i));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
case EArgObject:
|
||||
if (!Info[i]->IsObject())
|
||||
{
|
||||
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a object."), i));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace PUERTS_NAMESPACE
|
||||
|
||||
#define CHECK_V8_ARGS_LEN(Length) \
|
||||
if (!FV8Utils::CheckArgumentLength(Info, Length)) \
|
||||
{ \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define CHECK_V8_ARGS(...) \
|
||||
static std::vector<ArgType> ArgExpect = {__VA_ARGS__}; \
|
||||
if (!FV8Utils::CheckArgument(Info, ArgExpect)) \
|
||||
{ \
|
||||
return; \
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef PS_API_H_
|
||||
#define PS_API_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Portable Embedded Scripting API
|
||||
|
||||
#define PESAPI_VERSION 11
|
||||
|
||||
#define PESAPI_EXTERN
|
||||
|
||||
#if defined(__APPLE__) && defined(BUILDING_PES_EXTENSION) && !defined(PESAPI_ADPT_C)
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
|
||||
#define USING_OBJC_REFLECTION
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USING_OBJC_REFLECTION
|
||||
#import <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PESAPI_MODULE_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define PESAPI_MODULE_EXPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define PESAPI_NO_RETURN __attribute__((noreturn))
|
||||
#elif defined(_WIN32)
|
||||
#define PESAPI_NO_RETURN __declspec(noreturn)
|
||||
#else
|
||||
#define PESAPI_NO_RETURN
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN_C_START \
|
||||
extern "C" \
|
||||
{
|
||||
#define EXTERN_C_END }
|
||||
#else
|
||||
#define EXTERN_C_START
|
||||
#define EXTERN_C_END
|
||||
#endif
|
||||
|
||||
#define PESAPI_MODULE_INITIALIZER_X(base, module, version) PESAPI_MODULE_INITIALIZER_X_HELPER(base, module, version)
|
||||
|
||||
#define PESAPI_MODULE_INITIALIZER_X_HELPER(base, module, version) base##module##_v##version
|
||||
|
||||
#define PESAPI_MODULE_INITIALIZER_BASE pesapi_register_
|
||||
|
||||
#define PESAPI_MODULE_INITIALIZER(modname) PESAPI_MODULE_INITIALIZER_X(PESAPI_MODULE_INITIALIZER_BASE, modname, PESAPI_VERSION)
|
||||
|
||||
#define PESAPI_MODULE_VERSION() PESAPI_MODULE_INITIALIZER_X(PESAPI_MODULE_INITIALIZER_BASE, version, 0)
|
||||
|
||||
#ifdef USING_OBJC_REFLECTION
|
||||
|
||||
#define PESAPI_MODULE(modname, initfunc) \
|
||||
@interface PESAPI_MODULE_INITIALIZER (modname) : NSObject \
|
||||
@end \
|
||||
@implementation PESAPI_MODULE_INITIALIZER (modname) \
|
||||
+(void) initlib : (pesapi_func_ptr*) func_ptr_array \
|
||||
{ \
|
||||
pesapi_init(func_ptr_array); \
|
||||
initfunc(); \
|
||||
} \
|
||||
@end
|
||||
|
||||
#else
|
||||
|
||||
#define PESAPI_MODULE(modname, initfunc) \
|
||||
EXTERN_C_START \
|
||||
PESAPI_MODULE_EXPORT void PESAPI_MODULE_INITIALIZER(modname)(pesapi_func_ptr * func_ptr_array); \
|
||||
PESAPI_MODULE_EXPORT const char* PESAPI_MODULE_INITIALIZER(dynamic)(pesapi_func_ptr * func_ptr_array); \
|
||||
PESAPI_MODULE_EXPORT int PESAPI_MODULE_VERSION()(); \
|
||||
EXTERN_C_END \
|
||||
PESAPI_MODULE_EXPORT void PESAPI_MODULE_INITIALIZER(modname)(pesapi_func_ptr * func_ptr_array) \
|
||||
{ \
|
||||
pesapi_init(func_ptr_array); \
|
||||
initfunc(); \
|
||||
} \
|
||||
PESAPI_MODULE_EXPORT const char* PESAPI_MODULE_INITIALIZER(dynamic)(pesapi_func_ptr * func_ptr_array) \
|
||||
{ \
|
||||
if (func_ptr_array) \
|
||||
{ \
|
||||
pesapi_init(func_ptr_array); \
|
||||
initfunc(); \
|
||||
} \
|
||||
return #modname; \
|
||||
} \
|
||||
PESAPI_MODULE_EXPORT int PESAPI_MODULE_VERSION()() \
|
||||
{ \
|
||||
return PESAPI_VERSION; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
EXTERN_C_START
|
||||
|
||||
// alloc on stack
|
||||
struct pesapi_scope_memory
|
||||
{
|
||||
int padding__[32];
|
||||
};
|
||||
|
||||
typedef struct pesapi_env__* pesapi_env;
|
||||
typedef struct pesapi_env_ref__* pesapi_env_ref;
|
||||
typedef struct pesapi_value__* pesapi_value;
|
||||
typedef struct pesapi_value_ref__* pesapi_value_ref;
|
||||
typedef struct pesapi_callback_info__* pesapi_callback_info;
|
||||
typedef struct pesapi_scope__* pesapi_scope;
|
||||
typedef struct pesapi_type_info__* pesapi_type_info;
|
||||
typedef struct pesapi_signature_info__* pesapi_signature_info;
|
||||
typedef struct pesapi_property_descriptor__* pesapi_property_descriptor;
|
||||
|
||||
typedef void (*pesapi_callback)(pesapi_callback_info info);
|
||||
typedef void* (*pesapi_constructor)(pesapi_callback_info info);
|
||||
typedef void (*pesapi_finalize)(void* ptr, void* class_data, void* env_private);
|
||||
typedef void* (*pesapi_on_native_object_enter)(void* ptr, void* class_data, void* env_private);
|
||||
// userdata: return of pesapi_on_native_object_enter
|
||||
typedef void (*pesapi_on_native_object_exit)(void* ptr, void* class_data, void* env_private, void* userdata);
|
||||
typedef bool (*pesapi_class_not_found_callback)(const void* type_id);
|
||||
typedef void (*pesapi_func_ptr)(void);
|
||||
|
||||
#ifdef BUILDING_PES_EXTENSION
|
||||
PESAPI_EXTERN void pesapi_init(pesapi_func_ptr* func_array);
|
||||
#else
|
||||
PESAPI_MODULE_EXPORT int pesapi_load_addon(const char* path, const char* module_name);
|
||||
#endif
|
||||
|
||||
// value process
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_null(pesapi_env env);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_undefined(pesapi_env env);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_boolean(pesapi_env env, bool value);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_int32(pesapi_env env, int32_t value);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_uint32(pesapi_env env, uint32_t value);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_int64(pesapi_env env, int64_t value);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_uint64(pesapi_env env, uint64_t value);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_double(pesapi_env env, double value);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_string_utf8(pesapi_env env, const char* str, size_t length);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_binary(pesapi_env env, void* str, size_t length);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_array(pesapi_env env);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_object(pesapi_env env);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_function(pesapi_env env, pesapi_callback native_impl, void* data);
|
||||
PESAPI_EXTERN pesapi_value pesapi_create_class(pesapi_env env, const void* type_id);
|
||||
|
||||
PESAPI_EXTERN bool pesapi_get_value_bool(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN int32_t pesapi_get_value_int32(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN uint32_t pesapi_get_value_uint32(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN int64_t pesapi_get_value_int64(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN uint64_t pesapi_get_value_uint64(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN double pesapi_get_value_double(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN const char* pesapi_get_value_string_utf8(pesapi_env env, pesapi_value value, char* buf, size_t* bufsize);
|
||||
PESAPI_EXTERN void* pesapi_get_value_binary(pesapi_env env, pesapi_value pvalue, size_t* bufsize);
|
||||
PESAPI_EXTERN uint32_t pesapi_get_array_length(pesapi_env env, pesapi_value value);
|
||||
|
||||
PESAPI_EXTERN bool pesapi_is_null(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_undefined(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_boolean(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_int32(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_uint32(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_int64(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_uint64(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_double(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_string(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_object(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_function(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_binary(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_array(pesapi_env env, pesapi_value value);
|
||||
|
||||
PESAPI_EXTERN pesapi_value pesapi_native_object_to_value(pesapi_env env, const void* type_id, void* object_ptr, bool call_finalize);
|
||||
PESAPI_EXTERN void* pesapi_get_native_object_ptr(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN const void* pesapi_get_native_object_typeid(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_instance_of(pesapi_env env, const void* type_id, pesapi_value value);
|
||||
|
||||
PESAPI_EXTERN pesapi_value pesapi_boxing(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN pesapi_value pesapi_unboxing(pesapi_env env, pesapi_value value);
|
||||
PESAPI_EXTERN void pesapi_update_boxed_value(pesapi_env env, pesapi_value boxed_value, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_is_boxed_value(pesapi_env env, pesapi_value value);
|
||||
|
||||
PESAPI_EXTERN int pesapi_get_args_len(pesapi_callback_info info);
|
||||
PESAPI_EXTERN pesapi_value pesapi_get_arg(pesapi_callback_info info, int index);
|
||||
PESAPI_EXTERN pesapi_env pesapi_get_env(pesapi_callback_info info);
|
||||
PESAPI_EXTERN pesapi_value pesapi_get_this(pesapi_callback_info info);
|
||||
PESAPI_EXTERN pesapi_value pesapi_get_holder(pesapi_callback_info info);
|
||||
PESAPI_EXTERN void* pesapi_get_userdata(pesapi_callback_info info);
|
||||
PESAPI_EXTERN void pesapi_add_return(pesapi_callback_info info, pesapi_value value);
|
||||
PESAPI_EXTERN void pesapi_throw_by_string(pesapi_callback_info pinfo, const char* msg);
|
||||
|
||||
PESAPI_EXTERN pesapi_env_ref pesapi_create_env_ref(pesapi_env env);
|
||||
PESAPI_EXTERN bool pesapi_env_ref_is_valid(pesapi_env_ref env);
|
||||
PESAPI_EXTERN pesapi_env pesapi_get_env_from_ref(pesapi_env_ref env_ref);
|
||||
PESAPI_EXTERN pesapi_env_ref pesapi_duplicate_env_ref(pesapi_env_ref env_ref);
|
||||
PESAPI_EXTERN void pesapi_release_env_ref(pesapi_env_ref env_ref);
|
||||
|
||||
PESAPI_EXTERN pesapi_scope pesapi_open_scope(pesapi_env_ref env_ref);
|
||||
PESAPI_EXTERN pesapi_scope pesapi_open_scope_placement(pesapi_env_ref env_ref, struct pesapi_scope_memory* memory);
|
||||
PESAPI_EXTERN bool pesapi_has_caught(pesapi_scope scope);
|
||||
PESAPI_EXTERN const char* pesapi_get_exception_as_string(pesapi_scope scope, bool with_stack);
|
||||
PESAPI_EXTERN void pesapi_close_scope(pesapi_scope scope);
|
||||
PESAPI_EXTERN void pesapi_close_scope_placement(pesapi_scope scope);
|
||||
|
||||
PESAPI_EXTERN pesapi_value_ref pesapi_create_value_ref(pesapi_env env, pesapi_value value, uint32_t internal_field_count);
|
||||
PESAPI_EXTERN pesapi_value_ref pesapi_duplicate_value_ref(pesapi_value_ref value_ref);
|
||||
PESAPI_EXTERN void pesapi_release_value_ref(pesapi_value_ref value_ref);
|
||||
PESAPI_EXTERN pesapi_value pesapi_get_value_from_ref(pesapi_env env, pesapi_value_ref value_ref);
|
||||
PESAPI_EXTERN void pesapi_set_ref_weak(pesapi_env env, pesapi_value_ref value_ref);
|
||||
// Optional api: return false if can not fulfill
|
||||
PESAPI_EXTERN bool pesapi_set_owner(pesapi_env env, pesapi_value value, pesapi_value owner);
|
||||
// suggestion: struct pesapi_value_ref : pesapi_env_ref {...};
|
||||
PESAPI_EXTERN pesapi_env_ref pesapi_get_ref_associated_env(pesapi_value_ref value_ref);
|
||||
PESAPI_EXTERN void** pesapi_get_ref_internal_fields(pesapi_value_ref value_ref, uint32_t* pinternal_field_count);
|
||||
|
||||
PESAPI_EXTERN pesapi_value pesapi_get_property(pesapi_env env, pesapi_value object, const char* key);
|
||||
PESAPI_EXTERN void pesapi_set_property(pesapi_env env, pesapi_value object, const char* key, pesapi_value value);
|
||||
PESAPI_EXTERN bool pesapi_get_private(pesapi_env env, pesapi_value object, void** out_ptr);
|
||||
PESAPI_EXTERN bool pesapi_set_private(pesapi_env env, pesapi_value object, void* ptr);
|
||||
|
||||
PESAPI_EXTERN pesapi_value pesapi_get_property_uint32(pesapi_env env, pesapi_value object, uint32_t key);
|
||||
PESAPI_EXTERN void pesapi_set_property_uint32(pesapi_env env, pesapi_value object, uint32_t key, pesapi_value value);
|
||||
|
||||
PESAPI_EXTERN pesapi_value pesapi_call_function(
|
||||
pesapi_env env, pesapi_value func, pesapi_value this_object, int argc, const pesapi_value argv[]);
|
||||
|
||||
PESAPI_EXTERN pesapi_value pesapi_eval(pesapi_env env, const uint8_t* code, size_t code_size, const char* path);
|
||||
|
||||
PESAPI_EXTERN pesapi_value pesapi_global(pesapi_env env);
|
||||
PESAPI_EXTERN const void* pesapi_get_env_private(pesapi_env env);
|
||||
PESAPI_EXTERN void pesapi_set_env_private(pesapi_env env, const void* ptr);
|
||||
|
||||
PESAPI_EXTERN pesapi_type_info pesapi_alloc_type_infos(size_t count);
|
||||
|
||||
PESAPI_EXTERN void pesapi_set_type_info(
|
||||
pesapi_type_info type_infos, size_t index, const char* name, bool is_pointer, bool is_const, bool is_ref, bool is_primitive);
|
||||
|
||||
PESAPI_EXTERN pesapi_signature_info pesapi_create_signature_info(
|
||||
pesapi_type_info return_type, size_t parameter_count, pesapi_type_info parameter_types);
|
||||
|
||||
PESAPI_EXTERN pesapi_property_descriptor pesapi_alloc_property_descriptors(size_t count);
|
||||
|
||||
// using pesapi_get_userdata obtain userdata in callback
|
||||
PESAPI_EXTERN void pesapi_set_method_info(pesapi_property_descriptor properties, size_t index, const char* name, bool is_static,
|
||||
pesapi_callback method, void* data, pesapi_signature_info signature_info);
|
||||
|
||||
PESAPI_EXTERN void pesapi_set_property_info(pesapi_property_descriptor properties, size_t index, const char* name, bool is_static,
|
||||
pesapi_callback getter, pesapi_callback setter, void* getter_data, void* setter_data, pesapi_type_info type_info);
|
||||
|
||||
PESAPI_EXTERN void pesapi_define_class(const void* type_id, const void* super_type_id, const char* type_name,
|
||||
pesapi_constructor constructor, pesapi_finalize finalize, size_t property_count, pesapi_property_descriptor properties,
|
||||
void* data);
|
||||
|
||||
PESAPI_EXTERN void* pesapi_get_class_data(const void* type_id, bool force_load);
|
||||
|
||||
PESAPI_EXTERN bool pesapi_trace_native_object_lifecycle(
|
||||
const void* type_id, pesapi_on_native_object_enter on_enter, pesapi_on_native_object_exit on_exit);
|
||||
|
||||
PESAPI_EXTERN void pesapi_on_class_not_found(pesapi_class_not_found_callback callback);
|
||||
|
||||
PESAPI_EXTERN void pesapi_class_type_info(const char* proto_magic_id, const void* type_id, const void* constructor_info,
|
||||
const void* methods_info, const void* functions_info, const void* properties_info, const void* variables_info);
|
||||
|
||||
PESAPI_EXTERN const void* pesapi_find_type_id(const char* module_name, const char* type_name);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user