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