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()