1 /*
2  * Copyright (c) 2021 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 FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_ENGINE_JSI_JSI_REF_H
17 #define FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_ENGINE_JSI_JSI_REF_H
18 
19 #include "frameworks/bridge/declarative_frontend/engine/jsi/jsi_types.h"
20 
21 namespace OHOS::Ace::Framework {
22 
23 template<typename T>
24 class JsiWeak;
25 
26 /**
27  *  \brief A class template that holds a strong reference to a javascript value.
28  *  Further in the text, when we talk about "javascript value" we refer to its representation within C++.
29  *  Such are Value, Object, Array, Function, etc.
30  *
31  *  A strong reference will increase the reference count of the holding javascript value when constructed,
32  *  copied or assigned, and will decrease the reference count when destroyed.
33  *
34  *  A strong reference to a javascript value should only be held when sharing it among owners that outlive
35  *  said value. All other cases should use \p JSWeak. For example a row containing several buttons should
36  *  hold a strong reference, but those buttons should hold a weak reference to the parent row if that is
37  *  what the application requires, otherwise a circular dependency is established and objects do not get
38  *  collected by the garbage collector.
39  *
40  *  \code{.cpp}
41  *  \endcode
42  *
43  *  3. \p FunctionCallback and \p MemberFunctionCallback corresponding to ESI callback signatures:
44  *  \code{.cpp}
45  *  \endcode
46  *
47  *
48  *  \tparam A javascript value (Value, Object, Array, Function, etc.)
49  *  \example
50  *  \code{.cpp}
51  *  \endcode
52  *
53  * \class JsiRef
54  * \alias JSRef
55  */
56 template<typename T>
57 class JsiRef {
58 public:
59     using wrappedT = panda::Local<panda::ObjectRef>;
60     using EcmaVM = panda::ecmascript::EcmaVM;
61 
JsiRef()62     JsiRef() {}
JsiRef(const T & val)63     explicit JsiRef(const T& val) : value_(val) {}
~JsiRef()64     ~JsiRef()
65     {
66         value_.Reset();
67     }
68 
69     template<typename S>
JsiRef(const JsiRef<S> & that)70     JsiRef(const JsiRef<S>& that) : value_(T::Cast(that.Get()))
71     {}
72 
73     // We do not want implicit conversions from weak to strong reference
JsiRef(const JsiWeak<T> & rhs)74     explicit JsiRef(const JsiWeak<T>& rhs)
75     {
76         *this = rhs.Lock();
77     }
78 
79     template<typename... Args>
Make(Args &&...args)80     static JsiRef<T> Make(Args&&... args)
81     {
82         auto obj = T { args... };
83         return JsiRef<T>(obj);
84     }
85 
86     template<typename... Args>
FastMake(const EcmaVM * vm,Args &&...args)87     static JsiRef<T> FastMake(const EcmaVM *vm, Args&&... args)
88     {
89         auto obj = T { vm, args... };
90         return JsiRef<T>(obj);
91     }
92 
Claim(T && val)93     static JsiRef<T> Claim(T&& val)
94     {
95         return JsiRef<T>(std::forward<T>(val));
96     }
97 
98     template<typename S>
Cast(const JsiRef<S> & that)99     static JsiRef<T> Cast(const JsiRef<S>& that)
100     {
101         return JsiRef<T>::Make(T::Cast(that.Get()));
102     }
103 
104     template<class... Args>
New(Args &&...args)105     static JsiRef<T> New(Args&&... args)
106     {
107         return JsiRef<T>::Make(T::New(std::forward<Args>(args)...));
108     }
109 
JsiRef(const JsiRef<T> & rhs)110     JsiRef(const JsiRef<T>& rhs) : value_(rhs.value_) {}
111 
JsiRef(JsiRef<T> && rhs)112     JsiRef(JsiRef<T>&& rhs) : value_(std::move(rhs.value_))
113     {
114         rhs.value_.Reset();
115     }
116 
117     JsiRef<T>& operator=(const JsiRef<T>& rhs)
118     {
119         value_.Reset();
120         value_ = rhs.value_;
121         return *this;
122     }
123 
124     JsiRef<T>& operator=(JsiRef<T>&& rhs)
125     {
126         value_.Reset();
127         value_ = std::move(rhs.value_);
128         rhs.value_.Reset();
129         return *this;
130     }
131 
IsEmpty()132     bool IsEmpty() const
133     {
134         return value_.IsEmpty();
135     }
136 
Reset()137     void Reset()
138     {
139         value_.Reset();
140     }
141 
142     template<typename U>
Unwrap()143     typename std::enable_if_t<std::is_same_v<T, JsiObject>, U*> Unwrap() const
144     {
145         return value_.template Unwrap<U>();
146     }
147 
148     const T& operator->() const
149     {
150         return value_;
151     }
152 
Get()153     T Get() const
154     {
155         return value_;
156     }
157 
158 private:
159     T value_;
160 };
161 
162 template<typename T>
163 class JsiWeak {
164 public:
165     using wrappedT = panda::Local<panda::ObjectRef>;
166 
JsiWeak()167     JsiWeak() {}
~JsiWeak()168     ~JsiWeak()
169     {
170         value_.Reset();
171     }
172 
JsiWeak(const JsiWeak<T> & rhs)173     JsiWeak(const JsiWeak<T>& rhs) : value_(rhs.value_)
174     {
175         value_.SetWeakCallback(this, Reset);
176     }
177 
JsiWeak(JsiWeak<T> && rhs)178     JsiWeak(JsiWeak<T>&& rhs) : value_(std::move(rhs.value_))
179     {
180         value_.SetWeakCallback(this, Reset);
181         rhs.value_.Reset();
182     }
183 
JsiWeak(const JsiRef<T> & rhs)184     explicit JsiWeak(const JsiRef<T>& rhs) : value_(rhs.Get())
185     {
186         value_.SetWeakCallback(this, Reset);
187     }
188 
189     JsiWeak<T>& operator=(const JsiWeak<T>& rhs)
190     {
191         value_.Reset();
192         value_ = rhs.value_;
193         value_.SetWeakCallback(this, Reset);
194         return *this;
195     }
196 
197     JsiWeak<T>& operator=(const JsiRef<T>& rhs)
198     {
199         value_ = rhs.Get();
200         value_.SetWeakCallback(this, Reset);
201         return *this;
202     }
203 
204     JsiWeak<T>& operator=(JsiWeak<T>&& rhs)
205     {
206         value_.Reset();
207         value_ = std::move(rhs.value_);
208         value_.SetWeakCallback(this, Reset);
209 
210         rhs.value_.Reset();
211         return *this;
212     }
213 
IsEmpty()214     bool IsEmpty() const
215     {
216         return value_.IsEmpty();
217     }
218 
Reset()219     void Reset()
220     {
221         value_.Reset();
222     }
223 
Lock()224     JsiRef<T> Lock() const
225     {
226         return JsiRef<T>(value_);
227     }
228 
Reset(void * ref)229     static void Reset(void *ref)
230     {
231         auto that = reinterpret_cast<JsiWeak<T>*>(ref);
232         that->Reset();
233     }
234 
235 private:
236     T value_;
237 };
238 
239 } // namespace OHOS::Ace::Framework
240 #endif
241