1 /*
2 * Copyright (C) 2025 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 #if __OHOS_PLATFORM__
17 // need to use a workaround
18 // as napi_set_instance_data/napi_get_instance_data
19 // seems to be implemented incorrectly in a way
20 // that shares single instance data and env for ALL modules.
21 #define USE_WORKAROUND 1
22 #else
23 #define USE_WORKAROUND 0
24 #endif
25
26 #if USE_WORKAROUND
27 #include <base/containers/unordered_map.h>
28 #endif
29
30 #include "array.h"
31 #include "function.h"
32 #include "object.h"
33 #include "utils.h"
34
35 namespace NapiApi {
36
MyInstanceState(napi_env env,napi_value obj)37 MyInstanceState::MyInstanceState(napi_env env, napi_value obj) : env_(env)
38 {
39 napi_create_reference(env_, obj, 1, &ref_);
40 }
41
~MyInstanceState()42 MyInstanceState::~MyInstanceState()
43 {
44 uint32_t res;
45 napi_reference_unref(env_, ref_, &res);
46 }
47
GetRef()48 napi_value MyInstanceState::GetRef()
49 {
50 napi_value tmp;
51 napi_get_reference_value(env_, ref_, &tmp);
52 return tmp;
53 }
54 #if USE_WORKAROUND
55 namespace {
56 // workaround os bug
57 class workaround {
58 public:
59 workaround() = default;
60 workaround(const workaround&) = delete;
workaround(workaround && other)61 workaround(workaround&& other) noexcept
62 {
63 cb = other.cb;
64 hint = other.hint;
65 data = other.data;
66 env = other.env;
67 other.cb = nullptr;
68 other.hint = nullptr;
69 other.data = nullptr;
70 other.env = nullptr;
71 }
72 workaround& operator=(const workaround& other) = delete;
operator =(workaround && other)73 workaround& operator=(workaround&& other) noexcept
74 {
75 cb = other.cb;
76 hint = other.hint;
77 data = other.data;
78 env = other.env;
79 other.cb = nullptr;
80 other.hint = nullptr;
81 other.data = nullptr;
82 other.env = nullptr;
83 return *this;
84 }
~workaround()85 ~workaround()
86 {
87 if (cb) {
88 cb(env, data, hint);
89 }
90 }
workaround(napi_env e,void * d,napi_finalize c,void * h)91 workaround(napi_env e, void* d, napi_finalize c, void* h) : env(e), data(d), cb(c), hint(h) {};
92 napi_finalize cb { nullptr };
93 void* hint { nullptr };
94 void* data { nullptr };
95 napi_env env { nullptr };
96 };
97 BASE_NS::unordered_map<uintptr_t, workaround> workaround_data;
98 }; // namespace
99 #endif
GetInstance(napi_env env,void ** data)100 void MyInstanceState::GetInstance(napi_env env, void** data)
101 {
102 if (!data || !env) {
103 return;
104 }
105 #if USE_WORKAROUND
106 // workaround os bug
107 if (!workaround_data.contains((uintptr_t)env)) {
108 *data = nullptr;
109 return;
110 }
111 *data = workaround_data[(uintptr_t)env].data;
112 #else
113 napi_get_instance_data(env, data);
114 #endif
115 }
SetInstance(napi_env env,void * data,napi_finalize finalize_cb,void * finalize_hint)116 void MyInstanceState::SetInstance(napi_env env, void* data, napi_finalize finalize_cb, void* finalize_hint)
117 {
118 if (!env) {
119 return;
120 }
121 #if USE_WORKAROUND
122 // workaround os bug
123 if (workaround_data.contains((uintptr_t)env)) {
124 auto& wd = workaround_data[(uintptr_t)env];
125 wd.env = env;
126 wd.data = data;
127 wd.cb = finalize_cb;
128 wd.hint = finalize_hint;
129 return;
130 }
131 workaround_data.insert({ (uintptr_t)env, { env, data, finalize_cb, finalize_hint } });
132 #else
133 napi_set_instance_data(env, data, finalize_cb, finalize_hint);
134 #endif
135 }
136
StoreCtor(BASE_NS::string_view name,napi_value ctor)137 void MyInstanceState::StoreCtor(BASE_NS::string_view name, napi_value ctor)
138 {
139 NapiApi::Object exp(env_, GetRef());
140 exp.Set(name, ctor);
141 }
142
FetchCtor(BASE_NS::string_view name)143 napi_value MyInstanceState::FetchCtor(BASE_NS::string_view name)
144 {
145 NapiApi::Object exp(env_, GetRef());
146 return exp.Get(name);
147 }
148
149 template<typename type>
ValidateType(napi_valuetype jstype,bool isArray)150 bool ValidateType(napi_valuetype jstype, bool isArray)
151 {
152 /*
153 napi_undefined,
154 napi_null,
155 napi_symbol,
156 napi_function,
157 napi_external,
158 napi_bigint,
159 */
160
161 if constexpr (BASE_NS::is_same_v<type, BASE_NS::string>) {
162 if (jstype == napi_string) {
163 return true;
164 }
165 }
166 if constexpr (BASE_NS::is_same_v<type, bool>) {
167 if (jstype == napi_boolean) {
168 return true;
169 }
170 }
171 // yup..
172 if constexpr (BASE_NS::is_same_v<type, float>) {
173 if (jstype == napi_number) {
174 return true;
175 }
176 }
177 if constexpr (BASE_NS::is_same_v<type, double>) {
178 if (jstype == napi_number) {
179 return true;
180 }
181 }
182 if constexpr (BASE_NS::is_same_v<type, uint32_t>) {
183 if (jstype == napi_number) {
184 return true;
185 }
186 }
187 if constexpr (BASE_NS::is_same_v<type, int32_t>) {
188 if (jstype == napi_number) {
189 return true;
190 }
191 }
192 if constexpr (BASE_NS::is_same_v<type, int64_t>) {
193 if (jstype == napi_number) {
194 return true;
195 }
196 }
197 if constexpr (BASE_NS::is_same_v<type, uint64_t>) {
198 if (jstype == napi_number) {
199 return true;
200 }
201 }
202 if constexpr (BASE_NS::is_same_v<type, NapiApi::Object>) {
203 if (jstype == napi_object) {
204 return true;
205 }
206 // allow undefined and null also
207 if (jstype == napi_undefined) {
208 return true;
209 }
210 if (jstype == napi_null) {
211 return true;
212 }
213 }
214 if constexpr (BASE_NS::is_same_v<type, NapiApi::Array>) {
215 if (jstype == napi_object) {
216 return isArray;
217 }
218 }
219 if constexpr (BASE_NS::is_same_v<type, NapiApi::Function>) {
220 if (jstype == napi_function) {
221 return true;
222 }
223 // allow undefined and null also
224 if (jstype == napi_undefined) {
225 return true;
226 }
227 if (jstype == napi_null) {
228 return true;
229 }
230 }
231 return false;
232 }
233
234 template bool ValidateType<BASE_NS::string>(napi_valuetype, bool);
235 template bool ValidateType<bool>(napi_valuetype, bool);
236 template bool ValidateType<float>(napi_valuetype, bool);
237 template bool ValidateType<double>(napi_valuetype, bool);
238 template bool ValidateType<uint32_t>(napi_valuetype, bool);
239 template bool ValidateType<int32_t>(napi_valuetype, bool);
240 template bool ValidateType<int64_t>(napi_valuetype, bool);
241 template bool ValidateType<uint64_t>(napi_valuetype, bool);
242 template bool ValidateType<NapiApi::Object>(napi_valuetype, bool);
243 template bool ValidateType<NapiApi::Function>(napi_valuetype, bool);
244 template bool ValidateType<NapiApi::Array>(napi_valuetype, bool);
245
246 } // namespace NapiApi
247