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 #include "proxy_object.h"
17
18 #include <algorithm>
19
20 #include <meta/api/make_callback.h>
21 #include <meta/api/property/property_event_handler.h>
22 #include <meta/api/util.h>
23
24 META_BEGIN_NAMESPACE()
25
26 namespace Internal {
27
~ProxyObject()28 ProxyObject::~ProxyObject()
29 {
30 if (GetMetadata()) {
31 ResetTargetListener();
32 for (auto&& p : Super::GetAllProperties()) {
33 p->OnChanged()->RemoveHandler(uintptr_t(this));
34 }
35 }
36 }
37
Build(const IMetadata::Ptr & data)38 bool ProxyObject::Build(const IMetadata::Ptr& data)
39 {
40 bool ret = Super::Build(data);
41 if (ret) {
42 Dynamic()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this]() {
43 if (Dynamic()->GetValue()) {
44 ListenTargetChanges();
45 RefreshProperties();
46 } else {
47 ResetTargetListener();
48 }
49 }));
50
51 for (auto&& p : Super::GetAllProperties()) {
52 p->OnChanged()->AddHandler(MakeCallback<IOnChanged>(
53 [this](auto p) {
54 if (p) {
55 OnPropertyChanged(p);
56 }
57 },
58 p),
59 uintptr_t(this));
60 }
61
62 if (auto meta = GetSelf<IMetadata>()) {
63 metaAdded_.Subscribe<IOnChildChanged>(
64 meta->GetPropertyContainer()->OnAdded(), [this](const auto& i) { OnPropertyAdded(i); });
65 metaRemoved_.Subscribe<IOnChildChanged>(
66 meta->GetPropertyContainer()->OnRemoved(), [this](const auto& i) { OnPropertyRemoved(i); });
67 }
68 UpdateSerializeState();
69 }
70 return ret;
71 }
72
SerializeEmbeddedProxy(IProperty::Ptr p)73 static bool SerializeEmbeddedProxy(IProperty::Ptr p)
74 {
75 // Check for embedded proxy objects
76 if (auto proxy = GetPointer<IProxyObject>(p)) {
77 if (auto f = interface_cast<IObjectFlags>(proxy)) {
78 return static_cast<bool>(f->GetObjectFlags() & ObjectFlagBits::SERIALIZE);
79 }
80 }
81 return false;
82 }
83
OnPropertyAdded(const ChildChangedInfo & info)84 void ProxyObject::OnPropertyAdded(const ChildChangedInfo& info)
85 {
86 if (auto p = interface_pointer_cast<IProperty>(info.object)) {
87 auto f = GetSelf<IObjectFlags>();
88 if (!updating_ && f && !(f->GetObjectFlags() & ObjectFlagBits::SERIALIZE)) {
89 META_NS::SetObjectFlags(f, ObjectFlagBits::SERIALIZE, ShouldSerialise(p));
90 }
91 p->OnChanged()->AddHandler(MakeCallback<IOnChanged>(
92 [this](auto p) {
93 if (p) {
94 OnPropertyChanged(p);
95 }
96 },
97 p),
98 uintptr_t(this));
99 }
100 }
101
OnPropertyRemoved(const ChildChangedInfo & info)102 void ProxyObject::OnPropertyRemoved(const ChildChangedInfo& info)
103 {
104 if (auto p = interface_cast<IProperty>(info.object)) {
105 p->OnChanged()->RemoveHandler(uintptr_t(this));
106 }
107 auto f = GetSelf<IObjectFlags>();
108 if (!updating_ && f && f->GetObjectFlags() & ObjectFlagBits::SERIALIZE) {
109 UpdateSerializeState();
110 }
111 }
112
OnPropertyChanged(const IProperty::Ptr & p)113 void ProxyObject::OnPropertyChanged(const IProperty::Ptr& p)
114 {
115 auto f = GetSelf<IObjectFlags>();
116 if (!updating_ && f) {
117 if (f->GetObjectFlags() & ObjectFlagBits::SERIALIZE) {
118 UpdateSerializeState();
119 } else {
120 META_NS::SetObjectFlags(f, ObjectFlagBits::SERIALIZE, ShouldSerialise(p));
121 }
122 }
123 }
124
ListenTargetChanges()125 void ProxyObject::ListenTargetChanges()
126 {
127 if (auto target = interface_pointer_cast<IMetadata>(GetTarget())) {
128 targetAddedListener_.Subscribe<IOnChildChanged>(
129 target->GetPropertyContainer()->OnAdded(), [&](auto) { RefreshProperties(); });
130 targetRemovedListener_.Subscribe<IOnChildChanged>(
131 target->GetPropertyContainer()->OnRemoved(), [&](auto) { RefreshProperties(); });
132 }
133 }
134
ResetTargetListener()135 void ProxyObject::ResetTargetListener()
136 {
137 targetAddedListener_.Unsubscribe();
138 targetRemovedListener_.Unsubscribe();
139 }
140
RefreshProperties()141 void ProxyObject::RefreshProperties()
142 {
143 updating_ = true;
144 if (auto target = interface_pointer_cast<IMetadata>(GetTarget())) {
145 auto props = BASE_NS::move(proxyProperties_);
146 for (auto&& p : props) {
147 if (auto tp = target->GetPropertyByName(p.first)) {
148 auto res = proxyProperties_.insert({ p.first, p.second });
149 res.first->second.Bind(tp);
150 } else {
151 Super::RemoveProperty(p.second.GetProperty());
152 }
153 }
154 } else {
155 // remove all we added
156 for (auto&& p : proxyProperties_) {
157 Super::RemoveProperty(p.second.GetProperty());
158 }
159 proxyProperties_.clear();
160 }
161 updating_ = false;
162 UpdateSerializeState();
163 }
164
GetTarget() const165 const IObject::Ptr ProxyObject::GetTarget() const
166 {
167 return target_.lock();
168 }
169
SetTarget(const IObject::Ptr & target)170 bool ProxyObject::SetTarget(const IObject::Ptr& target)
171 {
172 ResetTargetListener();
173 target_ = target;
174 if (Dynamic()->GetValue()) {
175 ListenTargetChanges();
176 }
177 RefreshProperties();
178 if (META_ACCESS_PROPERTY_VALUE(Mode) & ProxyMode::REFLECT_PROXY_HIERARCHY) {
179 ReflectHierarchy(target);
180 }
181 return true;
182 }
183
ReflectHierarchy(const IObject::Ptr & target)184 void ProxyObject::ReflectHierarchy(const IObject::Ptr& target)
185 {
186 auto m = interface_pointer_cast<IMetadata>(target);
187 if (!m) {
188 return;
189 }
190 for (auto&& p : Super::GetAllProperties()) {
191 // reflect only non-proxyable properties
192 if (!proxyProperties_.count(p->GetName())) {
193 if (auto proxy = GetPointer<IProxyObject>(p)) {
194 ReflectTargetForProperty(m, p->GetName(), proxy);
195 }
196 }
197 }
198 }
199
ReflectTargetForProperty(const IMetadata::Ptr & m,BASE_NS::string_view name,const IProxyObject::Ptr & proxy)200 void ProxyObject::ReflectTargetForProperty(
201 const IMetadata::Ptr& m, BASE_NS::string_view name, const IProxyObject::Ptr& proxy)
202 {
203 if (auto p = m->GetPropertyByName(name)) {
204 if (auto tp = GetPointer<IObject>(p)) {
205 proxy->SetTarget(tp);
206 }
207 }
208 }
209
GetOverrides() const210 BASE_NS::vector<IProperty::ConstPtr> ProxyObject::GetOverrides() const
211 {
212 BASE_NS::vector<IProperty::ConstPtr> res;
213 for (auto&& p : proxyProperties_) {
214 if (!p.second.IsDefaultValue()) {
215 res.push_back(p.second.GetProperty());
216 }
217 }
218 return res;
219 }
220
GetOverride(BASE_NS::string_view name) const221 IProperty::ConstPtr ProxyObject::GetOverride(BASE_NS::string_view name) const
222 {
223 auto it = proxyProperties_.find(name);
224 return it != proxyProperties_.end() && !it->second.IsDefaultValue() ? it->second.GetProperty() : nullptr;
225 }
226
GetProxyProperty(BASE_NS::string_view name) const227 IProperty::ConstPtr ProxyObject::GetProxyProperty(BASE_NS::string_view name) const
228 {
229 auto it = proxyProperties_.find(name);
230 return it != proxyProperties_.end() ? it->second.GetProperty() : nullptr;
231 }
232
SetPropertyTarget(const IProperty::Ptr & property)233 IProperty::Ptr ProxyObject::SetPropertyTarget(const IProperty::Ptr& property)
234 {
235 if (!property) {
236 return nullptr;
237 }
238 IProperty::Ptr res;
239 bool add = true;
240 auto it = proxyProperties_.find(property->GetName());
241 if (it != proxyProperties_.end()) {
242 auto bprop = it->second.GetProperty();
243 add = !bprop || bprop->GetTypeId() != property->GetTypeId();
244 if (add) {
245 proxyProperties_.erase(it);
246 } else {
247 it->second.Bind(property);
248 res = it->second.GetProperty();
249 }
250 }
251 if (add && property) {
252 if (auto p = Super::GetPropertyByName(property->GetName())) {
253 auto r = proxyProperties_.insert_or_assign(p->GetName(), DefaultValueBind(p));
254 r.first->second.Bind(property);
255 res = p;
256 } else {
257 res = AddProxyProperty(property);
258 }
259 }
260 return res;
261 }
262
AddProxyProperty(const IProperty::ConstPtr & tp)263 IProperty::Ptr ProxyObject::AddProxyProperty(const IProperty::ConstPtr& tp)
264 {
265 auto p = DuplicatePropertyType(META_NS::GetObjectRegistry(), tp);
266 if (p) {
267 auto res = proxyProperties_.insert_or_assign(p->GetName(), DefaultValueBind(p));
268 res.first->second.Bind(tp);
269 AddProperty(p);
270 }
271 return p;
272 }
273
AddProxyProperty(BASE_NS::string_view name)274 IProperty::Ptr ProxyObject::AddProxyProperty(BASE_NS::string_view name)
275 {
276 IProperty::Ptr p;
277 if (auto target = interface_pointer_cast<IMetadata>(GetTarget())) {
278 if (auto tp = target->GetPropertyByName(name)) {
279 p = AddProxyProperty(tp);
280 }
281 }
282 return p;
283 }
284
PopulateAllProperties()285 void ProxyObject::PopulateAllProperties()
286 {
287 if (auto target = interface_pointer_cast<IMetadata>(GetTarget())) {
288 for (auto&& p : target->GetAllProperties()) {
289 auto it = proxyProperties_.find(p->GetName());
290 if (it == proxyProperties_.end()) {
291 AddProxyProperty(p);
292 }
293 }
294 }
295 }
296
GetPropertyByName(BASE_NS::string_view name)297 IProperty::Ptr ProxyObject::GetPropertyByName(BASE_NS::string_view name)
298 {
299 auto p = Super::GetPropertyByName(name);
300 if (!p) {
301 p = AddProxyProperty(name);
302 }
303 return p;
304 }
305
GetPropertyByName(BASE_NS::string_view name) const306 IProperty::ConstPtr ProxyObject::GetPropertyByName(BASE_NS::string_view name) const
307 {
308 return const_cast<ProxyObject*>(this)->GetPropertyByName(name);
309 }
310
RemoveProperty(const IProperty::Ptr & p)311 void ProxyObject::RemoveProperty(const IProperty::Ptr& p)
312 {
313 Super::RemoveProperty(p);
314 proxyProperties_.erase(p->GetName());
315 }
316
GetAllProperties()317 BASE_NS::vector<IProperty::Ptr> ProxyObject::GetAllProperties()
318 {
319 PopulateAllProperties();
320 return Super::GetAllProperties();
321 }
322
GetAllProperties() const323 BASE_NS::vector<IProperty::ConstPtr> ProxyObject::GetAllProperties() const
324 {
325 const_cast<ProxyObject*>(this)->PopulateAllProperties();
326 return Super::GetAllProperties();
327 }
328
ShouldSerialise(const IProperty::Ptr & p) const329 bool ProxyObject::ShouldSerialise(const IProperty::Ptr& p) const
330 {
331 auto s = interface_cast<IStackProperty>(p);
332 return (s && !s->GetValues({}, false).empty()) ||
333 (!IsFlagSet(p, ObjectFlagBits::NATIVE) && !proxyProperties_.count(p->GetName())) ||
334 SerializeEmbeddedProxy(p);
335 }
336
UpdateSerializeState()337 void ProxyObject::UpdateSerializeState()
338 {
339 if (!updating_) {
340 bool serialise = !GetOverrides().empty();
341 if (!serialise) {
342 for (auto&& p : Super::GetAllProperties()) {
343 serialise = ShouldSerialise(p);
344 if (serialise) {
345 break;
346 }
347 }
348 }
349 META_NS::SetObjectFlags(GetSelf(), ObjectFlagBits::SERIALIZE, serialise);
350 }
351 }
352
353 } // namespace Internal
354
355 META_END_NAMESPACE()
356