• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_CONVERT_BASE_H
17 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_CONVERT_BASE_H
18 
19 #include "plugins/ets/runtime/ets_panda_file_items.h"
20 #include "plugins/ets/runtime/interop_js/interop_common.h"
21 #include "plugins/ets/runtime/interop_js/js_value.h"
22 #include "runtime/handle_scope-inl.h"
23 #include "runtime/include/coretypes/class.h"
24 #include "plugins/ets/runtime/types/ets_array.h"
25 #include "plugins/ets/runtime/types/ets_arraybuffer.h"
26 #include "plugins/ets/runtime/types/ets_string.h"
27 #include "plugins/ets/runtime/types/ets_bigint.h"
28 #include "plugins/ets/runtime/types/ets_promise.h"
29 #include "plugins/ets/runtime/types/ets_promise_ref.h"
30 #include "plugins/ets/runtime/types/ets_box_primitive-inl.h"
31 #include "plugins/ets/runtime/types/ets_method.h"
32 #include "plugins/ets/runtime/interop_js/js_remote_promise_resolver.h"
33 
34 namespace ark::ets::interop::js {
35 
36 template <typename T>
AsEtsObject(T * obj)37 inline EtsObject *AsEtsObject(T *obj)
38 {
39     static_assert(std::is_base_of_v<ObjectHeader, T>);
40     return reinterpret_cast<EtsObject *>(obj);
41 }
42 
43 template <typename T>
FromEtsObject(EtsObject * obj)44 inline T *FromEtsObject(EtsObject *obj)
45 {
46     static_assert(std::is_base_of_v<ObjectHeader, T>);
47     return reinterpret_cast<T *>(obj);
48 }
49 
50 void JSConvertTypeCheckFailed(const char *typeName);
JSConvertTypeCheckFailed(const std::string & s)51 inline void JSConvertTypeCheckFailed(const std::string &s)
52 {
53     JSConvertTypeCheckFailed(s.c_str());
54 }
55 
56 // Base mixin class of JSConvert interface
57 // Represents primitive types and some built-in classes, has no state
58 template <typename Impl, typename ImplCpptype>
59 struct JSConvertBase {
60     JSConvertBase() = delete;
61     using cpptype = ImplCpptype;
62     static constexpr bool IS_REFTYPE = std::is_pointer_v<cpptype>;
63     static constexpr size_t TYPE_SIZE = IS_REFTYPE ? ClassHelper::OBJECT_POINTER_SIZE : sizeof(cpptype);
64 
TypeCheckFailedJSConvertBase65     static void TypeCheckFailed()
66     {
67         JSConvertTypeCheckFailed(Impl::TYPE_NAME);
68     }
69 
70     // Convert ets->js, returns nullptr if failed, throws JS exceptions
WrapJSConvertBase71     static napi_value Wrap(napi_env env, cpptype etsVal)
72     {
73         if constexpr (IS_REFTYPE) {
74             ASSERT(etsVal != nullptr);
75         }
76         auto res = Impl::WrapImpl(env, etsVal);
77         ASSERT(res != nullptr || InteropCtx::SanityJSExceptionPending());
78         return res;
79     }
80 
81     // Convert js->ets, returns nullopt if failed, throws ETS/JS exceptions
UnwrapJSConvertBase82     static std::optional<cpptype> Unwrap(InteropCtx *ctx, napi_env env, napi_value jsVal)
83     {
84         if constexpr (IS_REFTYPE) {
85             ASSERT(!IsNull(env, jsVal));
86         }
87         auto res = Impl::UnwrapImpl(ctx, env, jsVal);
88         ASSERT(res.has_value() || InteropCtx::SanityJSExceptionPending() || InteropCtx::SanityETSExceptionPending());
89         return res;
90     }
91 
WrapWithNullCheckJSConvertBase92     static napi_value WrapWithNullCheck(napi_env env, cpptype etsVal)
93     {
94         if constexpr (IS_REFTYPE) {
95             if (UNLIKELY(etsVal == nullptr)) {
96                 return GetNull(env);
97             }
98         }
99         auto res = Impl::WrapImpl(env, etsVal);
100         ASSERT(res != nullptr || InteropCtx::SanityJSExceptionPending());
101         return res;
102     }
103 
UnwrapWithNullCheckJSConvertBase104     static std::optional<cpptype> UnwrapWithNullCheck(InteropCtx *ctx, napi_env env, napi_value jsVal)
105     {
106         if constexpr (IS_REFTYPE) {
107             // NOTE(kprokopenko) can't assign undefined to EtsString *, hence fallback into UnwrapImpl
108             if (UNLIKELY(IsNull(env, jsVal))) {
109                 return nullptr;
110             }
111         }
112         auto res = Impl::UnwrapImpl(ctx, env, jsVal);
113         ASSERT(res.has_value() || InteropCtx::SanityJSExceptionPending() || InteropCtx::SanityETSExceptionPending());
114         return res;
115     }
116 };
117 
118 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
119 #define JSCONVERT_DEFINE_TYPE(type, cpptype_)                                                                \
120     struct JSConvert##type : public JSConvertBase<JSConvert##type, cpptype_> {                               \
121         static constexpr const char *TYPE_NAME = #type;                                                      \
122         /* Must not fail */                                                                                  \
123         [[maybe_unused]] static inline napi_value WrapImpl([[maybe_unused]] napi_env env,                    \
124                                                            [[maybe_unused]] cpptype etsVal);                 \
125         /* May fail */                                                                                       \
126         [[maybe_unused]] static inline std::optional<cpptype> UnwrapImpl([[maybe_unused]] InteropCtx *ctx,   \
127                                                                          [[maybe_unused]] napi_env env,      \
128                                                                          [[maybe_unused]] napi_value jsVal); \
129     }
130 
131 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
132 #define JSCONVERT_WRAP(type) \
133     inline napi_value JSConvert##type::WrapImpl([[maybe_unused]] napi_env env, [[maybe_unused]] cpptype etsVal)
134 
135 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
136 #define JSCONVERT_UNWRAP(type)                                                  \
137     inline std::optional<JSConvert##type::cpptype> JSConvert##type::UnwrapImpl( \
138         [[maybe_unused]] InteropCtx *ctx, [[maybe_unused]] napi_env env, [[maybe_unused]] napi_value jsVal)
139 }  // namespace ark::ets::interop::js
140 
141 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_JS_CONVERT_BASE_H
142