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 #ifndef META_API_PROPERTY_ARRAY_ELEMENT_BIND_H
17 #define META_API_PROPERTY_ARRAY_ELEMENT_BIND_H
18
19 #include <meta/ext/event_impl.h>
20 #include <meta/interface/property/property.h>
21
META_BEGIN_NAMESPACE()22 META_BEGIN_NAMESPACE()
23
24 /// Helper to bind individual array elements
25 class ArrayElementBind : public IntroduceInterfaces<IValue, INotifyOnChange> {
26 public:
27 ArrayElementBind(const IProperty::Ptr& p, size_t index) : p_(p), index_(index)
28 {
29 if (auto i = interface_cast<IPropertyInternalAny>(p)) {
30 if (auto&& any = i->GetInternalAny()) {
31 if (any->IsArray()) {
32 value_ = any->Clone({ CloneValueType::DEFAULT_VALUE, TypeIdRole::ITEM });
33 }
34 }
35 }
36 if (!value_) {
37 CORE_LOG_E("Failed to set any for array element bind");
38 value_ = GetObjectRegistry().GetPropertyRegister().InvalidAny().Clone(false);
39 }
40 p->OnChanged()->AddHandler(MakeCallback<IOnChanged>([&] {
41 if (!settingValue_) {
42 event_->Invoke();
43 }
44 }),
45 (uintptr_t)this);
46 }
47 ~ArrayElementBind()
48 {
49 if (auto p = p_.lock()) {
50 p->OnChanged()->RemoveHandler((uintptr_t)this);
51 }
52 }
53 BASE_NS::shared_ptr<IEvent> EventOnChanged(MetadataQuery) const override
54 {
55 return event_;
56 }
57 AnyReturnValue SetValue(const IAny& value) override
58 {
59 if (auto p = p_.lock()) {
60 AnyReturnValue ret = AnyReturn::FAIL;
61 settingValue_ = true;
62 {
63 ArrayPropertyLock l(p);
64 ret = l->SetAnyAt(index_, value);
65 }
66 settingValue_ = false;
67 return ret;
68 }
69 return AnyReturn::FAIL;
70 }
71 const IAny& GetValue() const override
72 {
73 if (auto p = p_.lock()) {
74 ArrayPropertyLock l(p);
75 l->GetAnyAt(index_, *value_);
76 }
77 return *value_;
78 }
79 bool IsCompatible(const TypeId& id) const override
80 {
81 return META_NS::IsCompatible(*value_, id);
82 }
83
84 private:
85 std::atomic<bool> settingValue_ {};
86 BASE_NS::shared_ptr<EventImpl<IOnChanged>> event_ { new EventImpl<IOnChanged>("OnChanged") };
87 IProperty::WeakPtr p_;
88 IAny::Ptr value_;
89 std::size_t index_ {};
90 };
91
92 /// Bind property to single element of array property
AddArrayElementBind(const IProperty::Ptr & p,const IProperty::Ptr & arr,size_t index)93 inline void AddArrayElementBind(const IProperty::Ptr& p, const IProperty::Ptr& arr, size_t index)
94 {
95 if (auto i = interface_cast<IStackProperty>(p)) {
96 BASE_NS::shared_ptr<ArrayElementBind> bind(new ArrayElementBind(arr, index));
97 i->PushValue(interface_pointer_cast<IValue>(bind));
98 }
99 }
100
101 META_END_NAMESPACE()
102
103 #endif
104