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 OHOS_ABILITY_RUNTIME_JS_RUNTIME_UTILS_H
17 #define OHOS_ABILITY_RUNTIME_JS_RUNTIME_UTILS_H
18
19 #include <cstdint>
20 #include <memory>
21 #include <sstream>
22 #include <type_traits>
23
24 #include "napi/native_api.h"
25 #include "native_engine/native_engine.h"
26
27 #include "js_runtime.h"
28
29 namespace OHOS {
30 namespace AbilityRuntime {
31 constexpr size_t ARGC_MAX_COUNT = 10;
32
33 #define NAPI_CALL_NO_THROW(theCall, retVal) \
34 do { \
35 if ((theCall) != napi_ok) { \
36 return retVal; \
37 } \
38 } while (0)
39
40 #define GET_CB_INFO_AND_CALL(env, info, T, func) \
41 do { \
42 size_t argc = ARGC_MAX_COUNT; \
43 napi_value argv[ARGC_MAX_COUNT] = {nullptr}; \
44 T* me = static_cast<T*>(GetCbInfoFromCallbackInfo(env, info, &argc, argv)); \
45 return (me != nullptr) ? me->func(env, argc, argv) : nullptr; \
46 } while (0)
47
48 struct NapiCallbackInfo {
49 size_t argc = ARGC_MAX_COUNT;
50 napi_value argv[ARGC_MAX_COUNT] = {nullptr};
51 napi_value thisVar = nullptr;
52 };
53
54 #define GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, T, func, name) \
55 do { \
56 NapiCallbackInfo napiInfo; \
57 T* me = static_cast<T*>(GetNapiCallbackInfoAndThis(env, info, napiInfo, name)); \
58 return (me != nullptr) ? me->func(env, napiInfo) : nullptr; \
59 } while (0)
60
61 #define GET_NAPI_INFO_AND_CALL(env, info, T, func) \
62 GET_NAPI_INFO_WITH_NAME_AND_CALL(env, info, T, func, nullptr)
63
64 void* GetNapiCallbackInfoAndThis(
65 napi_env env, napi_callback_info info, NapiCallbackInfo& napiInfo, const char* name = nullptr);
66
67 template<typename T, size_t N>
ArraySize(T (&)[N])68 inline constexpr size_t ArraySize(T (&)[N]) noexcept
69 {
70 return N;
71 }
72
CreateJsUndefined(napi_env env)73 inline napi_value CreateJsUndefined(napi_env env)
74 {
75 napi_value result = nullptr;
76 napi_get_undefined(env, &result);
77 return result;
78 }
79
CreateJsNull(napi_env env)80 inline napi_value CreateJsNull(napi_env env)
81 {
82 napi_value result = nullptr;
83 napi_get_null(env, &result);
84 return result;
85 }
86
CreateJsNumber(napi_env env,int32_t value)87 inline napi_value CreateJsNumber(napi_env env, int32_t value)
88 {
89 napi_value result = nullptr;
90 napi_create_int32(env, value, &result);
91 return result;
92 }
93
CreateJsNumber(napi_env env,uint32_t value)94 inline napi_value CreateJsNumber(napi_env env, uint32_t value)
95 {
96 napi_value result = nullptr;
97 napi_create_uint32(env, value, &result);
98 return result;
99 }
100
CreateJsNumber(napi_env env,int64_t value)101 inline napi_value CreateJsNumber(napi_env env, int64_t value)
102 {
103 napi_value result = nullptr;
104 napi_create_int64(env, value, &result);
105 return result;
106 }
107
CreateJsNumber(napi_env env,double value)108 inline napi_value CreateJsNumber(napi_env env, double value)
109 {
110 napi_value result = nullptr;
111 napi_create_double(env, value, &result);
112 return result;
113 }
114
115 template<class T>
CreateJsValue(napi_env env,const T & value)116 inline napi_value CreateJsValue(napi_env env, const T& value)
117 {
118 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
119 napi_value result = nullptr;
120 if constexpr (std::is_same_v<ValueType, bool>) {
121 napi_get_boolean(env, value, &result);
122 return result;
123 } else if constexpr (std::is_arithmetic_v<ValueType>) {
124 return CreateJsNumber(env, value);
125 } else if constexpr (std::is_same_v<ValueType, std::string>) {
126 napi_create_string_utf8(env, value.c_str(), value.length(), &result);
127 return result;
128 } else if constexpr (std::is_enum_v<ValueType>) {
129 return CreateJsNumber(env, static_cast<std::make_signed_t<ValueType>>(value));
130 } else if constexpr (std::is_same_v<ValueType, const char*>) {
131 (value != nullptr) ? napi_create_string_utf8(env, value, strlen(value), &result) :
132 napi_get_undefined(env, &result);
133 return result;
134 }
135 }
136
ConvertFromJsNumber(napi_env env,napi_value jsValue,int32_t & value)137 inline bool ConvertFromJsNumber(napi_env env, napi_value jsValue, int32_t& value)
138 {
139 NAPI_CALL_NO_THROW(napi_get_value_int32(env, jsValue, &value), false);
140 return true;
141 }
142
ConvertFromJsNumber(napi_env env,napi_value jsValue,uint32_t & value)143 inline bool ConvertFromJsNumber(napi_env env, napi_value jsValue, uint32_t& value)
144 {
145 NAPI_CALL_NO_THROW(napi_get_value_uint32(env, jsValue, &value), false);
146 return true;
147 }
148
ConvertFromJsNumber(napi_env env,napi_value jsValue,int64_t & value)149 inline bool ConvertFromJsNumber(napi_env env, napi_value jsValue, int64_t& value)
150 {
151 NAPI_CALL_NO_THROW(napi_get_value_int64(env, jsValue, &value), false);
152 return true;
153 }
154
ConvertFromJsNumber(napi_env env,napi_value jsValue,double & value)155 inline bool ConvertFromJsNumber(napi_env env, napi_value jsValue, double& value)
156 {
157 NAPI_CALL_NO_THROW(napi_get_value_double(env, jsValue, &value), false);
158 return true;
159 }
160
161 template<class T>
ConvertFromJsValue(napi_env env,napi_value jsValue,T & value)162 inline bool ConvertFromJsValue(napi_env env, napi_value jsValue, T& value)
163 {
164 if (jsValue == nullptr) {
165 return false;
166 }
167
168 using ValueType = std::remove_cv_t<std::remove_reference_t<T>>;
169 if constexpr (std::is_same_v<ValueType, bool>) {
170 NAPI_CALL_NO_THROW(napi_get_value_bool(env, jsValue, &value), false);
171 return true;
172 } else if constexpr (std::is_arithmetic_v<ValueType>) {
173 return ConvertFromJsNumber(env, jsValue, value);
174 } else if constexpr (std::is_same_v<ValueType, std::string>) {
175 size_t len = 0;
176 NAPI_CALL_NO_THROW(napi_get_value_string_utf8(env, jsValue, nullptr, 0, &len), false);
177 auto buffer = std::make_unique<char[]>(len + 1);
178 size_t strLength = 0;
179 NAPI_CALL_NO_THROW(napi_get_value_string_utf8(env, jsValue, buffer.get(), len + 1, &strLength), false);
180 value = buffer.get();
181 return true;
182 } else if constexpr (std::is_enum_v<ValueType>) {
183 std::make_signed_t<ValueType> numberValue = 0;
184 if (!ConvertFromJsNumber(env, jsValue, numberValue)) {
185 return false;
186 }
187 value = static_cast<ValueType>(numberValue);
188 return true;
189 }
190 }
191
192 template<class T>
CreateNativeArray(napi_env env,const std::vector<T> & data)193 napi_value CreateNativeArray(napi_env env, const std::vector<T>& data)
194 {
195 napi_value arrayValue = nullptr;
196 napi_create_array_with_length(env, data.size(), &arrayValue);
197 uint32_t index = 0;
198 for (const T& item : data) {
199 napi_set_element(env, arrayValue, index++, CreateJsValue(env, item));
200 }
201 return arrayValue;
202 }
203
204 napi_value CreateJsError(napi_env env, int32_t errCode, const std::string& message = std::string());
205 void BindNativeFunction(napi_env env, napi_value object, const char* name,
206 const char* moduleName, napi_callback func);
207 void BindNativeProperty(napi_env env, napi_value object, const char* name, napi_callback getter);
208 void* GetNativePointerFromCallbackInfo(napi_env env, napi_callback_info info, const char* name);
209 void* GetCbInfoFromCallbackInfo(napi_env env, napi_callback_info info, size_t* argc, napi_value* argv);
210
211 void SetNamedNativePointer(
212 napi_env env, napi_value object, const char* name, void* ptr, napi_finalize func);
213 void* GetNamedNativePointer(napi_env env, napi_value object, const char* name);
214
215 bool CheckTypeForNapiValue(napi_env env, napi_value param, napi_valuetype expectType);
216
217 template<class T>
218 T* CheckParamsAndGetThis(napi_env env, napi_callback_info info, const char* name = nullptr)
219 {
220 return static_cast<T*>(GetNativePointerFromCallbackInfo(env, info, name));
221 }
222
223 class HandleScope final {
224 public:
225 explicit HandleScope(JsRuntime& jsRuntime);
226 explicit HandleScope(napi_env env);
227 ~HandleScope();
228
229 HandleScope(const HandleScope&) = delete;
230 HandleScope(HandleScope&&) = delete;
231 HandleScope& operator=(const HandleScope&) = delete;
232 HandleScope& operator=(HandleScope&&) = delete;
233 private:
234 napi_handle_scope scope_ = nullptr;
235 napi_env env_ = nullptr;
236 };
237
238 class HandleEscape final {
239 public:
240 explicit HandleEscape(JsRuntime& jsRuntime);
241 explicit HandleEscape(napi_env env);
242 ~HandleEscape();
243
244 napi_value Escape(napi_value value);
245
246 HandleEscape(const HandleEscape&) = delete;
247 HandleEscape(HandleEscape&&) = delete;
248 HandleEscape& operator=(const HandleEscape&) = delete;
249 HandleEscape& operator=(HandleEscape&&) = delete;
250 private:
251 napi_escapable_handle_scope scope_ = nullptr;
252 napi_env env_ = nullptr;
253 };
254
255 class NapiAsyncTask final {
256 public:
257 using ExecuteCallback = std::function<void()>;
258 using CompleteCallback = std::function<void(napi_env, NapiAsyncTask&, int32_t)>;
259
260 static void Schedule(const std::string& name, napi_env env, std::unique_ptr<NapiAsyncTask>&& task);
261 static void ScheduleWithDefaultQos(const std::string &name, napi_env env,
262 std::unique_ptr<NapiAsyncTask>&& task);
263 static void ScheduleHighQos(const std::string& name, napi_env env, std::unique_ptr<NapiAsyncTask>&& task);
264 static void ScheduleLowQos(const std::string& name, napi_env env, std::unique_ptr<NapiAsyncTask>&& task);
265 bool StartWithDefaultQos(const std::string &name, napi_env env);
266
267 NapiAsyncTask(napi_deferred deferred, std::unique_ptr<ExecuteCallback>&& execute,
268 std::unique_ptr<CompleteCallback>&& complete);
269 NapiAsyncTask(napi_ref callbackRef, std::unique_ptr<ExecuteCallback>&& execute,
270 std::unique_ptr<CompleteCallback>&& complete);
271 ~NapiAsyncTask();
272
273 void Resolve(napi_env env, napi_value value);
274 void Reject(napi_env env, napi_value error);
275 void ResolveWithNoError(napi_env env, napi_value value);
276 void ResolveWithCustomize(napi_env env, napi_value error, napi_value value);
277 void RejectWithCustomize(napi_env env, napi_value error, napi_value value);
278 private:
279 static void Execute(napi_env env, void* data);
280 static void Complete(napi_env env, napi_status status, void* data);
281
282 bool Start(const std::string &name, napi_env env);
283 bool StartHighQos(const std::string &name, napi_env env);
284 bool StartLowQos(const std::string &name, napi_env env);
285
286 napi_deferred deferred_ = nullptr;
287 napi_ref callbackRef_ = nullptr;
288 napi_async_work work_ = nullptr;
289 std::unique_ptr<ExecuteCallback> execute_;
290 std::unique_ptr<CompleteCallback> complete_;
291 napi_env env_ = nullptr;
292 };
293
294 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
295 NapiAsyncTask::ExecuteCallback&& execute, NapiAsyncTask::CompleteCallback&& complete, napi_value* result);
296
297 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
298 NapiAsyncTask::ExecuteCallback&& execute, std::nullptr_t, napi_value* result);
299
300 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
301 std::nullptr_t, NapiAsyncTask::CompleteCallback&& complete, napi_value* result);
302
303 std::unique_ptr<NapiAsyncTask> CreateAsyncTaskWithLastParam(napi_env env, napi_value lastParam,
304 std::nullptr_t, std::nullptr_t, napi_value* result);
305
306 std::unique_ptr<NapiAsyncTask> CreateEmptyAsyncTask(napi_env env, napi_value lastParam, napi_value* result);
307 } // namespace AbilityRuntime
308 } // namespace OHOS
309 #endif // OHOS_ABILITY_RUNTIME_JS_RUNTIME_UTILS_H
310