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