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_INTERFACE_DETAIL_PROPERTY_H
17 #define META_INTERFACE_DETAIL_PROPERTY_H
18 
19 #include <base/containers/type_traits.h>
20 
21 #include <meta/interface/detail/any.h>
22 #include <meta/interface/intf_lockable.h>
23 #include <meta/interface/intf_object_registry.h>
24 #include <meta/interface/intf_value.h>
25 #include <meta/interface/property/intf_property.h>
26 #include <meta/interface/property/intf_property_internal.h>
27 #include <meta/interface/property/intf_property_register.h>
28 #include <meta/interface/property/intf_stack_property.h>
29 
META_BEGIN_NAMESPACE()30 META_BEGIN_NAMESPACE()
31 
32 class ConstTypelessPropertyInterface {
33 public:
34     using PropertyType = const IProperty*;
35 
36     explicit ConstTypelessPropertyInterface(PropertyType p) : p_(p) {}
37 
38     BASE_NS::string GetName() const
39     {
40         return p_->GetName();
41     }
42     IObject::WeakPtr GetOwner() const
43     {
44         return p_->GetOwner();
45     }
46 
47     const IAny& GetValueAny() const
48     {
49         return p_->GetValue();
50     }
51 
52     const IAny& GetDefaultValueAny() const
53     {
54         IAny::ConstPtr ret;
55         if (auto i = interface_cast<IStackProperty>(p_)) {
56             return i->GetDefaultValue();
57         }
58         return META_NS::GetObjectRegistry().GetPropertyRegister().InvalidAny();
59     }
60 
61     bool IsDefaultValue() const
62     {
63         return p_->IsDefaultValue();
64     }
65     bool IsValueSet() const
66     {
67         return !p_->IsDefaultValue();
68     }
69 
70     TypeId GetTypeId() const
71     {
72         return p_->GetTypeId();
73     }
74 
75     bool IsCompatible(const TypeId& id) const
76     {
77         return p_->IsCompatible(id);
78     }
79 
80     auto OnChanged() const
81     {
82         return p_->OnChanged();
83     }
84 
85     void NotifyChange() const
86     {
87         p_->NotifyChange();
88     }
89 
90     PropertyType GetProperty() const
91     {
92         return p_;
93     }
94 
95     const IStackProperty* GetStackProperty() const
96     {
97         return interface_cast<IStackProperty>(p_);
98     }
99 
100     template<typename Interface>
101     BASE_NS::vector<typename Interface::Ptr> GetModifiers() const
102     {
103         BASE_NS::vector<typename Interface::Ptr> res;
104         if (auto i = interface_cast<IStackProperty>(p_)) {
105             const TypeId view[] = { Interface::UID };
106             for (auto& v : i->GetModifiers(view, true)) {
107                 res.push_back(interface_pointer_cast<Interface>(v));
108             }
109         }
110         return res;
111     }
112 
113     IFunction::ConstPtr GetBind() const
114     {
115         if (auto i = interface_cast<IStackProperty>(p_)) {
116             const TypeId binds[] = { IBind::UID };
117             auto vec = i->GetValues(binds, false);
118             if (!vec.empty()) {
119                 if (auto bind = interface_cast<IBind>(vec.back())) {
120                     return bind->GetTarget();
121                 }
122             }
123         }
124         return nullptr;
125     }
126 
127 protected:
128     PropertyType p_;
129 };
130 
131 class TypelessPropertyInterface : public ConstTypelessPropertyInterface {
132 public:
133     using PropertyType = IProperty*;
134 
TypelessPropertyInterface(PropertyType p)135     TypelessPropertyInterface(PropertyType p) : ConstTypelessPropertyInterface(p), p_(p) {}
136 
SetValueAny(const IAny & any)137     AnyReturnValue SetValueAny(const IAny& any)
138     {
139         return p_->SetValue(any);
140     }
141 
SetDefaultValueAny(const IAny & value)142     AnyReturnValue SetDefaultValueAny(const IAny& value)
143     {
144         if (auto i = interface_cast<IStackProperty>(p_)) {
145             return i->SetDefaultValue(value);
146         }
147         return AnyReturn::FAIL;
148     }
149 
150     template<typename Intf>
PushValue(const BASE_NS::shared_ptr<Intf> & value)151     ReturnError PushValue(const BASE_NS::shared_ptr<Intf>& value)
152     {
153         if (auto i = interface_cast<IStackProperty>(p_)) {
154             if (auto v = interface_pointer_cast<IValue>(value)) {
155                 return i->PushValue(v);
156             }
157         }
158         return GenericError::FAIL;
159     }
160 
PopValue()161     ReturnError PopValue()
162     {
163         if (auto i = interface_cast<IStackProperty>(p_)) {
164             return i->PopValue();
165         }
166         return GenericError::FAIL;
167     }
168 
AddModifier(const IModifier::Ptr & mod)169     ReturnError AddModifier(const IModifier::Ptr& mod)
170     {
171         if (auto i = interface_cast<IStackProperty>(p_)) {
172             return i->AddModifier(mod);
173         }
174         return GenericError::FAIL;
175     }
176 
177     bool SetBind(const IFunction::ConstPtr& func, const BASE_NS::array_view<const INotifyOnChange::ConstPtr>& deps = {})
178     {
179         if (auto i = interface_cast<IStackProperty>(p_)) {
180             auto b = CreateBind(*i);
181             if (!b->SetTarget(func, deps.empty(), p_)) {
182                 return false;
183             }
184             for (auto& d : deps) {
185                 b->AddDependency(d);
186             }
187             return i->PushValue(interface_pointer_cast<IValue>(b));
188         }
189         return false;
190     }
191 
192     bool SetBind(const IProperty::ConstPtr& prop, const BASE_NS::array_view<const INotifyOnChange::ConstPtr>& deps = {})
193     {
194         if (auto i = interface_cast<IStackProperty>(p_)) {
195             auto b = CreateBind(*i);
196             if (!b->SetTarget(prop, deps.empty(), p_)) {
197                 return false;
198             }
199             for (auto& d : deps) {
200                 b->AddDependency(d);
201             }
202             return i->PushValue(interface_pointer_cast<IValue>(b));
203         }
204         return false;
205     }
206 
ResetBind()207     void ResetBind()
208     {
209         if (auto i = interface_cast<IStackProperty>(p_)) {
210             const TypeId binds[] = { IBind::UID };
211             auto vec = i->GetValues(binds, false);
212             if (!vec.empty()) {
213                 i->RemoveValue(vec.back());
214                 NotifyChange();
215             }
216         }
217     }
218 
ResetValue()219     void ResetValue()
220     {
221         p_->ResetValue();
222     }
223 
Reset()224     void Reset()
225     {
226         ResetValue();
227     }
228 
GetProperty()229     PropertyType GetProperty()
230     {
231         return p_;
232     }
233 
GetStackProperty()234     IStackProperty* GetStackProperty()
235     {
236         return interface_cast<IStackProperty>(p_);
237     }
238 
239 protected:
CreateBind(IStackProperty & prop)240     IBind::Ptr CreateBind(IStackProperty& prop)
241     {
242         if (interface_cast<IBind>(prop.TopValue())) {
243             prop.PopValue();
244         }
245         return META_NS::GetObjectRegistry().GetPropertyRegister().CreateBind();
246     }
247 
248 protected:
249     PropertyType p_;
250 };
251 
252 template<typename Type>
253 using PropertyBaseType =
254     BASE_NS::conditional_t<BASE_NS::is_const_v<Type>, ConstTypelessPropertyInterface, TypelessPropertyInterface>;
255 
256 template<typename Type>
257 class PropertyInterface : public PropertyBaseType<Type> {
258     using Super = PropertyBaseType<Type>;
259     using Super::p_;
260 
261 public:
262     using ValueType = BASE_NS::remove_const_t<Type>;
263     using PropertyType = typename Super::PropertyType;
264 
PropertyInterface(PropertyType p)265     explicit PropertyInterface(PropertyType p) : Super(p) {}
266 
GetDefaultValue()267     ValueType GetDefaultValue() const
268     {
269         ValueType v {};
270         this->GetDefaultValueAny().GetValue(v);
271         return v;
272     }
273 
SetDefaultValue(ValueType value,bool resetToDefault)274     AnyReturnValue SetDefaultValue(ValueType value, bool resetToDefault)
275     {
276         auto ret = this->SetDefaultValueAny(Any<ValueType>(value));
277         if (resetToDefault && ret) {
278             this->ResetValue();
279         }
280         return ret;
281     }
282 
SetDefaultValue(ValueType value)283     AnyReturnValue SetDefaultValue(ValueType value)
284     {
285         return SetDefaultValue(BASE_NS::move(value), false);
286     }
287 
GetValue()288     ValueType GetValue() const
289     {
290         ValueType v {};
291         this->GetValueAny().GetValue(v);
292         return v;
293     }
294 
SetValue(ValueType value)295     AnyReturnValue SetValue(ValueType value)
296     {
297         return this->SetValueAny(Any<ValueType>(value));
298     }
299 };
300 
301 template<typename Type>
302 class TypedPropertyLock final : public PropertyInterface<Type> {
303     using PropertyType = typename PropertyInterface<Type>::PropertyType;
304     using IT = PropertyInterface<Type>;
305     using InterfaceType = BASE_NS::conditional_t<BASE_NS::is_const_v<Type>, const IT*, IT*>;
306 
META_NO_COPY_MOVE(TypedPropertyLock)307     META_NO_COPY_MOVE(TypedPropertyLock)
308 
309 public:
310     explicit TypedPropertyLock(PropertyType p) : PropertyInterface<Type>(p)
311     {
312         if (auto i = interface_cast<ILockable>(p)) {
313             i->Lock();
314         }
315     }
~TypedPropertyLock()316     ~TypedPropertyLock()
317     {
318         if (auto i = interface_cast<ILockable>(this->GetProperty())) {
319             i->Unlock();
320         }
321     }
322 
323     InterfaceType operator->() const
324     {
325         return const_cast<TypedPropertyLock*>(this);
326     }
327 };
328 
329 template<typename Property>
330 class PropertyLock final : public PropertyBaseType<Property> {
331     using InterfaceType = PropertyBaseType<Property>*;
332 
META_NO_COPY_MOVE(PropertyLock)333     META_NO_COPY_MOVE(PropertyLock)
334 
335 public:
336     explicit PropertyLock(BASE_NS::shared_ptr<Property> p) : PropertyBaseType<Property>(p.get())
337     {
338         if (auto i = interface_cast<ILockable>(p)) {
339             i->Lock();
340         }
341     }
~PropertyLock()342     ~PropertyLock()
343     {
344         if (auto i = interface_cast<ILockable>(this->GetProperty())) {
345             i->Unlock();
346         }
347     }
348 
349     InterfaceType operator->() const
350     {
351         return const_cast<PropertyLock*>(this);
352     }
353 };
354 
355 META_END_NAMESPACE()
356 
357 #endif
358