1 /*
2  * Copyright (C) 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_RENDER_3D_NAPI_API
17 #define OHOS_RENDER_3D_NAPI_API
18 #define NAPI_VERSION 8
19 
20 #ifdef __OHOS_PLATFORM__
21 #include "napi/native_api.h"
22 #else
23 #include <node_api.h>
24 #endif
25 
26 #include <meta/interface/intf_object.h>
27 
28 #include <base/containers/string.h>
29 #include <base/containers/unique_ptr.h>
30 #include <base/containers/vector.h>
31 
32 #define LOG_F(...)
33 
34 namespace NapiApi {
35 template<typename type>
36 bool ValidateType(napi_valuetype jstype, bool isArray);
37 
38 template<typename type>
39 class Value {
40     napi_env env_ { nullptr };
41     napi_value value_ { nullptr };
42 
43 public:
44     using Type = type;
45     Value() = default;
Value(napi_env env,Type v)46     Value(napi_env env, Type v)
47     {
48         Init(env, v);
49     }
50 
51     void Init(napi_env env, Type v);
52 
Value(napi_env env,napi_value v)53     Value(napi_env env, napi_value v) : env_(env)
54     {
55         if ((env == nullptr) || (v == nullptr)) {
56             return;
57         }
58         // validate type
59         napi_valuetype jstype;
60         napi_status status = napi_invalid_arg;
61         status = napi_typeof(env_, v, &jstype);
62         if (status != napi_ok) {
63             // okay then failed.
64             return;
65         }
66         bool isArray = false;
67         napi_is_array(env_, v, &isArray);
68 
69         if (ValidateType<type>(jstype, isArray)) {
70             value_ = v;
71         }
72     }
IsValid()73     bool IsValid()
74     {
75         return (env_ && value_);
76     }
77     type valueOrDefault(const type defaultValue = {});
type()78     operator type()
79     {
80         return valueOrDefault();
81     }
GetEnv()82     napi_env GetEnv() const
83     {
84         return env_;
85     }
86 
napi_value()87     operator napi_value() const
88     {
89         return value_;
90     }
91 };
92 class Function;
93 
94 template<typename... Types>
95 class FunctionContext {
96     napi_value jsThis { nullptr };
97     void* data_ { nullptr };
98     const size_t argc { sizeof...(Types) };
99     napi_value args[sizeof...(Types) + 1] {};
100     napi_env env_ { nullptr };
101     napi_callback_info info_ { nullptr };
102 
103 public:
104     template<typename First, typename... Rest>
validate(size_t index)105     inline bool validate(size_t index)
106     {
107         napi_valuetype jstype;
108         napi_status status = napi_invalid_arg;
109         status = napi_typeof(env_, args[index], &jstype);
110         bool isArray = false;
111         napi_is_array(env_, args[index], &isArray);
112 
113         bool ret = ValidateType<First>(jstype, isArray);
114         if (ret) {
115             if constexpr (sizeof...(Rest) == 0) {
116                 return true;
117             }
118             if constexpr (sizeof...(Rest) > 0) {
119                 return validate<Rest...>(index + 1);
120             }
121         }
122         return false;
123     }
124     template<typename... ot>
FunctionContext(FunctionContext<ot...> other)125     FunctionContext(FunctionContext<ot...> other) : FunctionContext(other.GetEnv(), other.GetInfo())
126     {}
FunctionContext(const napi_env env,const napi_callback_info info)127     FunctionContext(const napi_env env, const napi_callback_info info)
128     {
129         if ((!env) || (!info)) {
130             return;
131         }
132         napi_status status;
133         size_t arg_count;
134         if constexpr (sizeof...(Types) == 0) {
135             // dont care about args now. or void args
136             env_ = env;
137             info_ = info;
138             status = napi_get_cb_info(env, info, &arg_count, nullptr, &jsThis, &data_);
139         }
140         if constexpr (sizeof...(Types) > 0) {
141             // check arg count first
142             status = napi_get_cb_info(env, info, &arg_count, nullptr, nullptr, nullptr);
143             if (argc != arg_count) {
144                 // non matching arg count. fail
145                 return;
146             }
147 
148             status = napi_get_cb_info(env, info, &arg_count, args, &jsThis, &data_);
149             env_ = env;
150             if (!validate<Types...>(0)) {
151                 // non matching types in context!
152                 env_ = {};
153                 return;
154             }
155             // Okay valid.
156             info_ = info;
157         }
158     }
159     operator bool()
160     {
161         return (env_ && info_);
162     }
GetData()163     void* GetData() const
164     {
165         return data_;
166     }
napi_env()167     operator napi_env() const
168     {
169         return env_;
170     }
GetEnv()171     napi_env GetEnv() const
172     {
173         return env_;
174     }
GetInfo()175     napi_callback_info GetInfo() const
176     {
177         return info_;
178     }
179 
This()180     napi_value This()
181     {
182         return jsThis;
183     }
value(size_t index)184     napi_value value(size_t index)
185     {
186         if (index < argc) {
187             return args[index];
188         }
189         return nullptr;
190     }
191 
192     template<size_t I, typename T, typename... TypesI>
193     struct GetTypeImpl {
194         using type = typename GetTypeImpl<I - 1, TypesI...>::type;
195     };
196     template<typename T, typename... TypesI>
197     struct GetTypeImpl<0, T, TypesI...> {
198         using type = T;
199     };
200 
201     template<size_t index>
202     auto Arg()
203     {
204         if constexpr (sizeof...(Types) > 0) {
205             if constexpr (index < sizeof...(Types)) {
206                 return Value<typename GetTypeImpl<index, Types...>::type> { env_, args[index] };
207             }
208             if constexpr (index >= sizeof...(Types)) {
209                 static_assert(index < sizeof...(Types), "Index out of range !");
210                 return Value<void*>((napi_env) nullptr, (void*)nullptr);
211             }
212         }
213         if constexpr (sizeof...(Types) == 0) {
214             return;
215         }
216     }
217 
218     // these could be forwarder to env..
219     napi_value GetUndefined()
220     {
221         if (!env_) {
222             return {};
223         }
224         napi_value undefined;
225         napi_get_undefined(env_, &undefined);
226         return undefined;
227     }
228     napi_value GetNull()
229     {
230         if (!env_) {
231             return {};
232         }
233         napi_value null;
234         napi_get_null(env_, &null);
235         return null;
236     }
237     napi_value GetBoolean(bool value)
238     {
239         if (!env_) {
240             return {};
241         }
242         napi_value val;
243         napi_get_boolean(env_, value, &val);
244         return val;
245     }
246 };
247 
248 class Object {
249     napi_env env_ { nullptr };
250     napi_value object_ { nullptr };
251 
252 public:
253     Object() = default;
254     Object(Function ctor);
255     Object(Function ctor, size_t argc, napi_value args[]);
256     Object(napi_env env) : env_(env)
257     {
258         napi_create_object(env, &object_);
259     }
260     Object(napi_env env, napi_value v) : env_(env), object_(v)
261     {
262         napi_valuetype jstype;
263         napi_typeof(env_, v, &jstype);
264         if (jstype != napi_object) {
265             // value was not an object!
266             env_ = nullptr;
267             object_ = nullptr;
268         }
269     }
270 
271     template<class T>
272     T* Native()
273     {
274         T* me = nullptr;
275         napi_unwrap(env_, object_, (void**)&me);
276         return me;
277     }
278     void Set(const BASE_NS::string_view name, napi_value value)
279     {
280         // could check if it is declared. and optionally add it. (now it just adds it if not declared)
281         napi_set_named_property(env_, object_, BASE_NS::string(name).c_str(), value);
282     }
283     void Set(const BASE_NS::string_view name, BASE_NS::string_view v)
284     {
285         napi_value value;
286         napi_status status = napi_create_string_utf8(env_, v.data(), v.length(), &value);
287         status = napi_set_named_property(env_, object_, BASE_NS::string(name).c_str(), value);
288     }
289     napi_value Get(const BASE_NS::string_view name)
290     {
291         napi_status status;
292         napi_value res;
293         status = napi_get_named_property(env_, object_, BASE_NS::string(name).c_str(), &res);
294         if (!res) {
295             return nullptr;
296         }
297         napi_valuetype jstype;
298         napi_typeof(env_, res, &jstype);
299         if (jstype == napi_null) {
300             return nullptr;
301         }
302         if (jstype == napi_undefined) {
303             return nullptr;
304         }
305         return res;
306     }
307     template<typename t>
308     Value<t> Get(const BASE_NS::string_view name)
309     {
310         return Value<t>(env_, Get(name));
311     }
312     operator napi_value() const
313     {
314         return object_;
315     }
316 
317     napi_env GetEnv() const
318     {
319         return env_;
320     }
321 };
322 
323 class Array {
324     napi_env env_ { nullptr };
325     napi_value array_ { nullptr };
326 
327 public:
328     Array() = default;
329     Array(napi_env env, size_t count) : env_(env)
330     {
331         napi_create_array_with_length(env, count, &array_);
332     }
333     Array(napi_env env, napi_value v)
334     {
335         napi_valuetype jstype;
336         napi_typeof(env, v, &jstype);
337         if (jstype != napi_object) {
338             return;
339         }
340         bool isArray = false;
341         napi_is_array(env, v, &isArray);
342         if (!isArray) {
343             return;
344         }
345         env_ = env;
346         array_ = v;
347     }
348 
349     operator napi_value() const
350     {
351         return array_;
352     }
353 
354     napi_env GetEnv() const
355     {
356         return env_;
357     }
358 
359     size_t Count() const
360     {
361         uint32_t size;
362         napi_get_array_length(env_, array_, &size);
363         return size;
364     }
365     void Set_value(size_t index, napi_value v) const
366     {
367         napi_set_element(env_, array_, index, v);
368     }
369 
370     napi_value Get_value(size_t index) const
371     {
372         napi_value result;
373         napi_get_element(env_, array_, index, &result);
374         return result;
375     }
376     napi_valuetype Type(size_t index) const
377     {
378         napi_value element;
379         napi_get_element(env_, array_, index, &element);
380         napi_valuetype jstype;
381         napi_status status = napi_invalid_arg;
382         status = napi_typeof(env_, element, &jstype);
383         return jstype;
384     }
385     template<typename T>
386     Value<T> Get(size_t index) const
387     {
388         return Value<T> { env_, Get_value(index) };
389     }
390     template<typename T>
391     void Set(size_t index, T t) const
392     {
393         Set_value(index, Value<T>(env_, t));
394     }
395 };
396 
397 class Function {
398     napi_env env_ { nullptr };
399     napi_value func_ { nullptr };
400 
401 public:
402     Function() = default;
403     Function(napi_env env, napi_value v) : env_(env), func_(v)
404     {
405         napi_valuetype jstype;
406         napi_typeof(env_, v, &jstype);
407         if (jstype != napi_function) {
408             // value was not an object!
409             env_ = nullptr;
410             func_ = nullptr;
411         }
412     }
413     operator napi_value() const
414     {
415         return func_;
416     }
417 
418     napi_env GetEnv() const
419     {
420         return env_;
421     }
422     napi_value Invoke(NapiApi::Object thisJS, size_t argc = 0, napi_value* argv = nullptr) const
423     {
424         napi_value res;
425         napi_call_function(env_, thisJS, func_, argc, argv, &res);
426         return res;
427     }
428 };
429 
430 class MyInstanceState {
431     napi_ref ref_;
432     napi_env env_;
433 
434 public:
435     MyInstanceState(napi_env env, napi_value obj) : env_(env)
436     {
437         napi_create_reference(env_, obj, 1, &ref_);
438     }
439     MyInstanceState(NapiApi::Object obj)
440     {
441         env_ = obj.GetEnv();
442         napi_create_reference(env_, obj, 1, &ref_);
443     }
444     ~MyInstanceState()
445     {
446         uint32_t res;
447         napi_reference_unref(env_, ref_, &res);
448     }
449     napi_value getRef()
450     {
451         napi_value tmp;
452         napi_get_reference_value(env_, ref_, &tmp);
453         return tmp;
454     }
455 
456     void StoreCtor(BASE_NS::string_view name, napi_value ctor)
457     {
458         NapiApi::Object exp(env_, getRef());
459         exp.Set(name, ctor);
460     }
461     napi_value FetchCtor(BASE_NS::string_view name)
462     {
463         NapiApi::Object exp(env_, getRef());
464         return exp.Get(name);
465     }
466 };
467 template<typename type>
468 bool ValidateType(napi_valuetype jstype, bool isArray)
469 {
470     /*
471       napi_undefined,
472       napi_null,
473       napi_symbol,
474       napi_function,
475       napi_external,
476       napi_bigint,
477     */
478 
479     if constexpr (BASE_NS::is_same_v<type, BASE_NS::string>) {
480         if (jstype == napi_string) {
481             return true;
482         }
483     }
484     if constexpr (BASE_NS::is_same_v<type, bool>) {
485         if (jstype == napi_boolean) {
486             return true;
487         }
488     }
489     // yup..
490     if constexpr (BASE_NS::is_same_v<type, float>) {
491         if (jstype == napi_number) {
492             return true;
493         }
494     }
495     if constexpr (BASE_NS::is_same_v<type, double>) {
496         if (jstype == napi_number) {
497             return true;
498         }
499     }
500     if constexpr (BASE_NS::is_same_v<type, uint32_t>) {
501         if (jstype == napi_number) {
502             return true;
503         }
504     }
505     if constexpr (BASE_NS::is_same_v<type, int32_t>) {
506         if (jstype == napi_number) {
507             return true;
508         }
509     }
510     if constexpr (BASE_NS::is_same_v<type, int64_t>) {
511         if (jstype == napi_number) {
512             return true;
513         }
514     }
515     if constexpr (BASE_NS::is_same_v<type, uint64_t>) {
516         if (jstype == napi_number) {
517             return true;
518         }
519     }
520     if constexpr (BASE_NS::is_same_v<type, NapiApi::Object>) {
521         if (jstype == napi_object) {
522             return true;
523         }
524         // allow undefined and null also
525         if (jstype == napi_undefined) {
526             return true;
527         }
528         if (jstype == napi_null) {
529             return true;
530         }
531     }
532     if constexpr (BASE_NS::is_same_v<type, NapiApi::Array>) {
533         if (jstype == napi_object) {
534             return isArray;
535         }
536     }
537     if constexpr (BASE_NS::is_same_v<type, NapiApi::Function>) {
538         if (jstype == napi_function) {
539             return true;
540         }
541     }
542     return false;
543 }
544 
545 template<typename type>
546 type NapiApi::Value<type>::valueOrDefault(const type defaultValue)
547 {
548     if (!value_) {
549         return defaultValue;
550     }
551     napi_status status = napi_invalid_arg;
552     type value {};
553     if constexpr (BASE_NS::is_same_v<type, BASE_NS::string>) {
554         size_t length;
555         status = napi_get_value_string_utf8(env_, value_, nullptr, 0, &length);
556         if (status != napi_ok) {
557             // return default if failed.
558             return defaultValue;
559         }
560         value.reserve(length + 1);
561         value.resize(length);
562         status = napi_get_value_string_utf8(env_, value_, value.data(), length + 1, &length);
563     }
564     if constexpr (BASE_NS::is_same_v<type, bool>) {
565         status = napi_get_value_bool(env_, value_, &value);
566     }
567     if constexpr (BASE_NS::is_same_v<type, float>) {
568         double tmp;
569         status = napi_get_value_double(env_, value_, &tmp);
570         value = tmp;
571     }
572     if constexpr (BASE_NS::is_same_v<type, double>) {
573         status = napi_get_value_double(env_, value_, &value);
574     }
575     if constexpr (BASE_NS::is_same_v<type, uint32_t>) {
576         status = napi_get_value_uint32(env_, value_, &value);
577     }
578     if constexpr (BASE_NS::is_same_v<type, int32_t>) {
579         status = napi_get_value_int32(env_, value_, &value);
580     }
581     if constexpr (BASE_NS::is_same_v<type, int64_t>) {
582         status = napi_get_value_int64(env_, value_, &value);
583     }
584     if constexpr (BASE_NS::is_same_v<type, uint64_t>) {
585         int64_t tmp;
586         status = napi_get_value_int64(env_, value_, &tmp);
587         value = static_cast<uint64_t>(tmp);
588     }
589     if constexpr (BASE_NS::is_same_v<type, NapiApi::Object>) {
590         status = napi_ok;
591         value = NapiApi::Object(env_, value_);
592     }
593     if constexpr (BASE_NS::is_same_v<type, NapiApi::Function>) {
594         status = napi_ok;
595         value = NapiApi::Function(env_, value_);
596     }
597     if constexpr (BASE_NS::is_same_v<type, NapiApi::Array>) {
598         status = napi_ok;
599         value = NapiApi::Array(env_, value_);
600     }
601     if (status != napi_ok) {
602         // return default if failed.
603         return defaultValue;
604     }
605     return value;
606 }
607 
608 inline Object::Object(Function ctor)
609 {
610     env_ = ctor.GetEnv();
611     napi_new_instance(env_, ctor, 0, nullptr, &object_);
612 }
613 
614 inline Object::Object(Function ctor, size_t argc, napi_value args[])
615 {
616     env_ = ctor.GetEnv();
617     napi_new_instance(env_, ctor, argc, args, &object_);
618 }
619 
620 template<typename Object, napi_value (Object::*F)(NapiApi::FunctionContext<>&)>
621 static inline napi_value Getter(napi_env env, napi_callback_info info)
622 {
623     NapiApi::FunctionContext fc(env, info);
624     if (fc) {
625         NapiApi::Object me(env, fc.This());
626         if (me) {
627             if (auto scj = me.Native<Object>()) {
628                 if (auto ret = (scj->*F)(fc)) {
629                     return ret;
630                 }
631             }
632         }
633     }
634     napi_value undefineVar;
635     napi_get_undefined(env, &undefineVar);
636     return undefineVar;
637 };
638 
639 template<typename Type, typename Object, void (Object::*F)(NapiApi::FunctionContext<Type>&)>
640 static inline napi_value Setter(napi_env env, napi_callback_info info)
641 {
642     NapiApi::FunctionContext<Type> fc(env, info);
643     if (fc) {
644         NapiApi::Object me(env, fc.This());
645         if (me) {
646             if (auto scj = me.Native<Object>()) {
647                 (scj->*F)(fc);
648             }
649         }
650     }
651     napi_value undefineVar;
652     napi_get_undefined(env, &undefineVar);
653     return undefineVar;
654 };
655 
656 template<typename FC, typename Object, napi_value (Object::*F)(FC&)>
657 static inline napi_value MethodI(napi_env env, napi_callback_info info)
658 {
659     FC fc(env, info);
660     if (fc) {
661         NapiApi::Object me(env, fc.This());
662         if (me) {
663             if (auto scj = me.Native<Object>()) {
664                 return (scj->*F)(fc);
665             }
666         }
667     }
668     napi_value undefineVar;
669     napi_get_undefined(env, &undefineVar);
670     return undefineVar;
671 };
672 
673 template<typename FC, typename Object, napi_value (Object::*F)(FC&)>
674 static inline napi_property_descriptor Method(
675     const char* const name, napi_property_attributes flags = napi_default_method)
676 {
677     return napi_property_descriptor { name, nullptr, MethodI<FC, Object, F>, nullptr, nullptr, nullptr, flags,
678         nullptr };
679 }
680 
681 template<typename Type, typename Object, void (Object::*F2)(NapiApi::FunctionContext<Type>&)>
682 static inline napi_property_descriptor SetProperty(
683     const char* const name, napi_property_attributes flags = napi_default_jsproperty)
684 {
685     static_assert(F2 != nullptr);
686     return napi_property_descriptor { name, nullptr, nullptr, nullptr, Setter<Type, Object, F2>, nullptr, flags,
687         nullptr };
688 }
689 
690 template<typename Type, typename Object, napi_value (Object::*F)(NapiApi::FunctionContext<>&)>
691 static inline napi_property_descriptor GetProperty(
692     const char* const name, napi_property_attributes flags = napi_default_jsproperty)
693 {
694     static_assert(F != nullptr);
695     return napi_property_descriptor { name, nullptr, nullptr, Getter<Object, F>, nullptr, nullptr, flags, nullptr };
696 }
697 
698 template<typename Type, typename Object, napi_value (Object::*F)(NapiApi::FunctionContext<>&),
699     void (Object::*F2)(NapiApi::FunctionContext<Type>&)>
700 static inline napi_property_descriptor GetSetProperty(
701     const char* const name, napi_property_attributes flags = napi_default_jsproperty)
702 {
703     static_assert(F != nullptr);
704     static_assert(F2 != nullptr);
705     return napi_property_descriptor { name, nullptr, nullptr, Getter<Object, F>, Setter<Type, Object, F2>, nullptr,
706         flags, nullptr };
707 }
708 class WeakRef {
709     napi_env env_ { nullptr };
710     napi_ref ref_ { nullptr };
711 
712 public:
713     WeakRef() = default;
714     WeakRef(NapiApi::WeakRef&& ref) noexcept
715     {
716         env_ = ref.env_;
717         ref_ = ref.ref_;
718         ref.env_ = nullptr;
719         ref.ref_ = nullptr;
720     }
721 
722     WeakRef(const NapiApi::WeakRef& ref)
723     {
724         if (!ref.IsEmpty()) {
725             napi_status stat;
726             env_ = ref.env_;
727             stat = napi_create_reference(env_, ref.GetValue(), 0, &ref_);
728         }
729     }
730     NapiApi::WeakRef operator=(NapiApi::WeakRef&& ref) noexcept
731     {
732         env_ = ref.env_;
733         ref_ = ref.ref_;
734         ref.env_ = nullptr;
735         ref.ref_ = nullptr;
736         return *this;
737     }
738     NapiApi::WeakRef operator=(const NapiApi::WeakRef& ref)
739     {
740         if (&ref != this) {
741             if (!ref.IsEmpty()) {
742                 napi_status stat;
743                 // unh just create a new one..
744                 env_ = ref.env_;
745                 stat = napi_create_reference(env_, ref.GetValue(), 0, &ref_);
746             }
747         }
748         return *this;
749     }
750     WeakRef(NapiApi::Object obj)
751     {
752         env_ = obj.GetEnv();
753         napi_create_reference(env_, obj, 0, &ref_);
754     }
755     WeakRef(napi_env env, napi_value obj)
756     {
757         env_ = env;
758         napi_create_reference(env_, obj, 0, &ref_);
759     }
760     ~WeakRef()
761     {
762         Reset();
763     }
764     bool IsEmpty() const
765     {
766         if (env_ && ref_) {
767             // possibly actually check the ref?
768             return false;
769         }
770         return true;
771     }
772     NapiApi::Object GetObject()
773     {
774         if (env_ && ref_) {
775             napi_value value;
776             napi_get_reference_value(env_, ref_, &value);
777             return NapiApi::Object(env_, value);
778         }
779         return {};
780     }
781     napi_env GetEnv()
782     {
783         return env_;
784     }
785     napi_value GetValue() const
786     {
787         if (env_ && ref_) {
788             napi_value value;
789             napi_get_reference_value(env_, ref_, &value);
790             return value;
791         }
792         return {};
793     }
794     void Reset()
795     {
796         if (env_ && ref_) {
797             napi_delete_reference(env_, ref_);
798         }
799         env_ = nullptr;
800         ref_ = nullptr;
801     }
802 };
803 
804 class StrongRef {
805     napi_env env_ { nullptr };
806     napi_ref ref_ { nullptr };
807 
808 public:
809     StrongRef() = default;
810     StrongRef(NapiApi::StrongRef&& ref) noexcept
811     {
812         env_ = ref.env_;
813         ref_ = ref.ref_;
814         ref.env_ = nullptr;
815         ref.ref_ = nullptr;
816     }
817 
818     StrongRef(const NapiApi::StrongRef& ref)
819     {
820         if (!ref.IsEmpty()) {
821             napi_status stat;
822             env_ = ref.env_;
823 
824             // unh just create a new one..
825             stat = napi_create_reference(env_, ref.GetValue(), 1, &ref_);
826         }
827     }
828     NapiApi::StrongRef operator=(NapiApi::StrongRef&& ref) noexcept
829     {
830         env_ = ref.env_;
831         ref_ = ref.ref_;
832         ref.env_ = nullptr;
833         ref.ref_ = nullptr;
834         return *this;
835     }
836     NapiApi::StrongRef operator=(const NapiApi::StrongRef& ref)
837     {
838         if (&ref != this) {
839             if (!ref.IsEmpty()) {
840                 napi_status stat;
841                 // unh just create a new one..
842                 env_ = ref.env_;
843                 stat = napi_create_reference(env_, ref.GetValue(), 1, &ref_);
844             }
845         }
846         return *this;
847     }
848     StrongRef(NapiApi::Object obj)
849     {
850         env_ = obj.GetEnv();
851         napi_create_reference(env_, obj, 1, &ref_);
852     }
853     StrongRef(napi_env env, napi_value obj)
854     {
855         env_ = env;
856         napi_create_reference(env_, obj, 1, &ref_);
857     }
858     ~StrongRef()
859     {
860         Reset();
861     }
862     bool IsEmpty() const
863     {
864         if (env_ && ref_) {
865             // possibly actually check the ref?
866             return false;
867         }
868         return true;
869     }
870     NapiApi::Object GetObject()
871     {
872         if (env_ && ref_) {
873             napi_value value;
874             napi_get_reference_value(env_, ref_, &value);
875             return NapiApi::Object(env_, value);
876         }
877         return {};
878     }
879     napi_env GetEnv()
880     {
881         return env_;
882     }
883     napi_value GetValue() const
884     {
885         if (env_ && ref_) {
886             napi_value value;
887             napi_get_reference_value(env_, ref_, &value);
888             return value;
889         }
890         return {};
891     }
892     void Reset()
893     {
894         if (env_ && ref_) {
895             napi_delete_reference(env_, ref_);
896         }
897         env_ = nullptr;
898         ref_ = nullptr;
899     }
900 };
901 
902 template<typename T>
903 void Value<T>::Init(napi_env env, Type v)
904 {
905     if (env == nullptr) {
906         return;
907     }
908     env_ = env;
909     if constexpr (BASE_NS::is_same_v<Type, float>) {
910         napi_create_double(env_, v, &value_);
911     }
912     if constexpr (BASE_NS::is_same_v<Type, double>) {
913         napi_create_double(env_, v, &value_);
914     }
915     if constexpr (BASE_NS::is_same_v<Type, uint32_t>) {
916         napi_create_uint32(env_, v, &value_);
917     }
918     if constexpr (BASE_NS::is_same_v<Type, int32_t>) {
919         napi_create_int32(env_, v, &value_);
920     }
921     if constexpr (BASE_NS::is_same_v<Type, int64_t>) {
922         napi_create_int64(env_, v, &value_);
923     }
924     if constexpr (BASE_NS::is_same_v<Type, uint64_t>) {
925         int64_t tmp = static_cast<int64_t>(v);
926         napi_create_int64(env_, tmp, &value_);
927     }
928     if constexpr (BASE_NS::is_same_v<Type, NapiApi::Object>) {
929         value_ = v;
930     }
931 }
932 
933 } // namespace NapiApi
934 NapiApi::Object FetchJsObj(const META_NS::IObject::Ptr& obj);
935 template<typename t>
936 NapiApi::Object FetchJsObj(const t& obj)
937 {
938     return FetchJsObj(interface_pointer_cast<META_NS::IObject>(obj));
939 }
940 // creates a new reference to jsobj. returns napi_value from reference.
941 NapiApi::Object StoreJsObj(const META_NS::IObject::Ptr& obj, NapiApi::Object jsobj);
942 NapiApi::Function GetJSConstructor(napi_env env, const BASE_NS::string_view jsName);
943 
944 // extracts the uri from "string" or "Resource"
945 BASE_NS::string FetchResourceOrUri(napi_env e, napi_value arg);
946 BASE_NS::string FetchResourceOrUri(NapiApi::FunctionContext<>& ctx);
947 
948 // little helper macros
949 
950 // declare NAPI_API_JS_NAME ...
951 #define NAPI_API_xs(s) NAPI_API_s(s)
952 #define NAPI_API_s(s) #s
953 #define NAPI_API_xcn(s) NAPI_API_cn(s)
954 #define NAPI_API_cn(s) s##JS
955 #define NAPI_API_JS_NAME_STRING NAPI_API_xs(NAPI_API_JS_NAME)
956 #define NAPI_API_CLASS_NAME NAPI_API_xcn(NAPI_API_JS_NAME)
957 
958 #define DeclareGet(type, name, getter) \
959     node_props.push_back(NapiApi::GetProperty<type, NAPI_API_CLASS_NAME, &NAPI_API_CLASS_NAME::getter>(name));
960 #define DeclareSet(type, name, setter) \
961     node_props.push_back(NapiApi::SetProperty<type, NAPI_API_CLASS_NAME, &NAPI_API_CLASS_NAME::setter>(name));
962 #define DeclareGetSet(type, name, getter, setter)                                                         \
963     node_props.push_back(NapiApi::GetSetProperty<type, NAPI_API_CLASS_NAME, &NAPI_API_CLASS_NAME::getter, \
964         &NAPI_API_CLASS_NAME::setter>(name));
965 #define DeclareMethod(name, function, ...)                                                                           \
966     node_props.push_back(                                                                                            \
967         NapiApi::Method<NapiApi::FunctionContext<__VA_ARGS__>, NAPI_API_CLASS_NAME, &NAPI_API_CLASS_NAME::function>( \
968             name));
969 #define DeclareClass()                                                                                      \
970     {                                                                                                       \
971         napi_value func;                                                                                    \
972         auto status = napi_define_class(env, NAPI_API_JS_NAME_STRING, NAPI_AUTO_LENGTH,                     \
973             BaseObject::ctor<NAPI_API_CLASS_NAME>(), nullptr, node_props.size(), node_props.data(), &func); \
974         NapiApi::MyInstanceState* mis;                                                                      \
975         napi_get_instance_data(env, (void**)&mis);                                                          \
976         mis->StoreCtor(NAPI_API_JS_NAME_STRING, func);                                                      \
977     }
978 
979 #endif // OHOS_RENDER_3D_NAPI_API