• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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