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 "bind.h"
17
18 #include <meta/ext/serialization/serializer.h>
19
20 #include "../any.h"
21 #include "dependencies.h"
22
23 META_BEGIN_NAMESPACE()
24 namespace Internal {
25
~Bind()26 Bind::~Bind()
27 {
28 for (auto it = dependencies_.begin(); it != dependencies_.end(); ++it) {
29 if (auto p = it->lock()) {
30 p->OnChanged()->RemoveHandler(uintptr_t(this));
31 }
32 }
33 }
34
SetValue(const IAny & value)35 AnyReturnValue Bind::SetValue(const IAny& value)
36 {
37 return AnyReturn::NOT_SUPPORTED;
38 }
GetValue() const39 const IAny& Bind::GetValue() const
40 {
41 if (func_ && context_) {
42 context_->Reset();
43 func_->Invoke(context_);
44 if (context_->Succeeded()) {
45 return *context_->GetResult();
46 }
47 }
48 CORE_LOG_W("GetValue called for invalid bind");
49 return INVALID_ANY;
50 }
IsCompatible(const TypeId & id) const51 bool Bind::IsCompatible(const TypeId& id) const
52 {
53 return context_ && context_->GetResult() && META_NS::IsCompatible(*context_->GetResult(), id);
54 }
SetTarget(const IProperty::ConstPtr & prop,bool getDeps,const IProperty * owner)55 bool Bind::SetTarget(const IProperty::ConstPtr& prop, bool getDeps, const IProperty* owner)
56 {
57 auto f = GetObjectRegistry().Create<IFunction>(META_NS::ClassId::PropertyFunction);
58 if (auto i = interface_cast<IPropertyFunction>(f)) {
59 i->SetTarget(prop);
60 if (SetTarget(f, getDeps, owner)) {
61 return AddDependency(prop);
62 }
63 }
64 return false;
65 }
SetTarget(const IFunction::ConstPtr & func,bool getDeps,const IProperty * owner)66 bool Bind::SetTarget(const IFunction::ConstPtr& func, bool getDeps, const IProperty* owner)
67 {
68 // inherit serializability from the function
69 META_NS::SetObjectFlags(static_cast<IObjectFlags*>(this), ObjectFlagBits::SERIALIZE,
70 META_NS::IsFlagSet(func, ObjectFlagBits::SERIALIZE));
71 func_ = func;
72 return func_ && CreateContext(getDeps, owner);
73 }
GetTarget() const74 IFunction::ConstPtr Bind::GetTarget() const
75 {
76 return func_;
77 }
AddDependency(const INotifyOnChange::ConstPtr & dep)78 bool Bind::AddDependency(const INotifyOnChange::ConstPtr& dep)
79 {
80 for (auto& d : dependencies_) {
81 if (dep == d.lock()) {
82 return true;
83 }
84 }
85 dep->OnChanged()->AddHandler(event_, uintptr_t(this));
86 dependencies_.push_back(dep);
87 return true;
88 }
RemoveDependency(const INotifyOnChange::ConstPtr & dep)89 bool Bind::RemoveDependency(const INotifyOnChange::ConstPtr& dep)
90 {
91 for (auto it = dependencies_.begin(); it != dependencies_.end(); ++it) {
92 if (it->lock() == dep) {
93 dep->OnChanged()->RemoveHandler(uintptr_t(this));
94 dependencies_.erase(it);
95 return true;
96 }
97 }
98 return false;
99 }
GetDependencies() const100 BASE_NS::vector<INotifyOnChange::ConstPtr> Bind::GetDependencies() const
101 {
102 BASE_NS::vector<INotifyOnChange::ConstPtr> deps;
103 for (auto&& v : dependencies_) {
104 if (auto d = v.lock()) {
105 deps.push_back(d);
106 }
107 }
108 return deps;
109 }
EventOnChanged(MetadataQuery) const110 BASE_NS::shared_ptr<IEvent> Bind::EventOnChanged(MetadataQuery) const
111 {
112 return event_;
113 }
Export(IExportContext & c) const114 ReturnError Bind::Export(IExportContext& c) const
115 {
116 return Serializer(c) & NamedValue("function", func_);
117 }
Import(IImportContext & c)118 ReturnError Bind::Import(IImportContext& c)
119 {
120 return Serializer(c) & NamedValue("function", func_);
121 }
Finalize(IImportFunctions &)122 ReturnError Bind::Finalize(IImportFunctions&)
123 {
124 if (func_) {
125 if (CreateContext(false, nullptr)) {
126 if (auto i = interface_cast<IPropertyFunction>(func_)) {
127 if (auto noti = interface_pointer_cast<INotifyOnChange>(i->GetDestination())) {
128 AddDependency(noti);
129 }
130 }
131 return GenericError::SUCCESS;
132 }
133 }
134 return GenericError::FAIL;
135 }
136
CreateContext(bool eval,const IProperty * owner)137 bool Bind::CreateContext(bool eval, const IProperty* owner)
138 {
139 context_ = func_->CreateCallContext();
140 if (context_ && eval) {
141 BASE_NS::vector<IProperty::ConstPtr> deps;
142
143 auto& d = GetDeps();
144 d.Start();
145 // Evaluate to collect dependencies
146 GetValue();
147 auto state = d.GetImmediateDependencies(deps);
148 if (state && owner && d.HasDependency(owner)) {
149 state = GenericError::RECURSIVE_CALL;
150 }
151 d.End();
152 if (!state) {
153 return false;
154 }
155 for (auto&& v : deps) {
156 if (auto noti = interface_pointer_cast<INotifyOnChange>(v)) {
157 AddDependency(noti);
158 }
159 }
160 }
161 return context_ != nullptr;
162 }
163
Reset()164 void Bind::Reset() {}
165
166 } // namespace Internal
167 META_END_NAMESPACE()