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

282 lines
7.3 KiB
C++

/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include "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