/* * 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 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 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::toCpp(env, value); } return {}; } template 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::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; }; class Function : public Object { public: Function(pesapi_env env, pesapi_value value) : Object(env, value) { } template 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 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::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 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::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 auto invokeHelper(pesapi_env env, pesapi_value func, Args... CppArgs) const { pesapi_value argv[sizeof...(Args)]{pesapi_impl::Converter::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; }; } // namespace pesapi_impl template <> struct ScriptTypeName { static constexpr auto value() { return internal::Literal("object"); } }; template <> struct ScriptTypeName { static constexpr auto value() { return internal::Literal("Function"); } }; namespace pesapi_impl { template <> struct Converter { 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 { 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