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 24META_BEGIN_NAMESPACE() 25 26namespace Internal { 27 28ProxyObject::~ProxyObject() 29{ 30 if (GetMetadata()) { 31 ResetTargetListener(); 32 for (auto&& p : Super::GetAllProperties()) { 33 p->OnChanged()->RemoveHandler(uintptr_t(this)); 34 } 35 } 36} 37 38bool 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 73static 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 84void 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 102void 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 113void 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 125void 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 135void ProxyObject::ResetTargetListener() 136{ 137 targetAddedListener_.Unsubscribe(); 138 targetRemovedListener_.Unsubscribe(); 139} 140 141void 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 165const IObject::Ptr ProxyObject::GetTarget() const 166{ 167 return target_.lock(); 168} 169 170bool 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 184void 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 200void 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 210BASE_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 221IProperty::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 227IProperty::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 233IProperty::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 263IProperty::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 274IProperty::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 285void 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 297IProperty::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 306IProperty::ConstPtr ProxyObject::GetPropertyByName(BASE_NS::string_view name) const 307{ 308 return const_cast<ProxyObject*>(this)->GetPropertyByName(name); 309} 310 311void ProxyObject::RemoveProperty(const IProperty::Ptr& p) 312{ 313 Super::RemoveProperty(p); 314 proxyProperties_.erase(p->GetName()); 315} 316 317BASE_NS::vector<IProperty::Ptr> ProxyObject::GetAllProperties() 318{ 319 PopulateAllProperties(); 320 return Super::GetAllProperties(); 321} 322 323BASE_NS::vector<IProperty::ConstPtr> ProxyObject::GetAllProperties() const 324{ 325 const_cast<ProxyObject*>(this)->PopulateAllProperties(); 326 return Super::GetAllProperties(); 327} 328 329bool 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 337void 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 355META_END_NAMESPACE() 356