• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_INTERNAL_OBJECT_API_H
17 #define META_API_INTERNAL_OBJECT_API_H
18 
19 #include <assert.h>
20 
21 #include <base/containers/type_traits.h>
22 #include <base/util/uid_util.h>
23 
24 #include <meta/api/property/binding.h>
25 #include <meta/interface/builtin_objects.h>
26 #include <meta/interface/intf_attachment.h>
27 #include <meta/interface/intf_metadata.h>
28 #include <meta/interface/intf_object_registry.h>
29 #include <meta/interface/property/array_property.h>
30 #include <meta/interface/property/construct_array_property.h>
31 #include <meta/interface/property/construct_property.h>
32 #include <meta/interface/property/property.h>
33 
34 // Fix compiler error due to naming clash with windows headers
35 #if defined(GetClassName)
36 #undef GetClassName
37 #endif
38 
META_BEGIN_NAMESPACE()39 META_BEGIN_NAMESPACE()
40 
41 namespace Internal {
42 
43 #define META_INTERFACE_API(ClassName)                                                                      \
44 private:                                                                                                   \
45     using FinalClassType = FinalClass;                                                                     \
46                                                                                                            \
47 public:                                                                                                    \
48     using META_NS::Object::operator=;                                                                      \
49     ClassName() noexcept = default;                                                                        \
50     ~ClassName() override = default;                                                                       \
51     ClassName(const ClassName& other) noexcept /* NOLINT(bugprone-copy-constructor-init)*/                 \
52     {                                                                                                      \
53         META_NS::Object::Initialize(other);                                                                \
54     }                                                                                                      \
55     ClassName(ClassName&& other) noexcept                                                                  \
56     {                                                                                                      \
57         META_NS::Object::Initialize(other);                                                                \
58         other.ResetIObject();                                                                              \
59     }                                                                                                      \
60     explicit ClassName(const META_NS::IObject::Ptr& other)                                                 \
61     {                                                                                                      \
62         META_NS::Object::Initialize(other);                                                                \
63     }                                                                                                      \
64     ClassName& operator=(const ClassName& other) noexcept                                                  \
65     {                                                                                                      \
66         return static_cast<ClassName&>(META_NS::Object::operator=(other));                                 \
67     }                                                                                                      \
68     ClassName& operator=(ClassName&& other) noexcept                                                       \
69     {                                                                                                      \
70         return static_cast<ClassName&>(META_NS::Object::operator=(static_cast<META_NS::Object&&>(other))); \
71     }
72 
73 #define META_API(ClassName)                                                                                \
74 private:                                                                                                   \
75     using FinalClassType = ClassName;                                                                      \
76                                                                                                            \
77 public:                                                                                                    \
78     using META_NS::Object::operator=;                                                                      \
79     ClassName() noexcept = default;                                                                        \
80     ~ClassName() override = default;                                                                       \
81     ClassName(const ClassName& other) noexcept /* NOLINT(bugprone-copy-constructor-init)*/                 \
82     {                                                                                                      \
83         META_NS::Object::Initialize(other);                                                                \
84     }                                                                                                      \
85     ClassName(ClassName&& other) noexcept                                                                  \
86     {                                                                                                      \
87         META_NS::Object::Initialize(other);                                                                \
88         other.ResetIObject();                                                                              \
89     }                                                                                                      \
90     explicit ClassName(const META_NS::IObject::Ptr& other)                                                 \
91     {                                                                                                      \
92         META_NS::Object::Initialize(other);                                                                \
93     }                                                                                                      \
94     ClassName& operator=(const ClassName& other) noexcept                                                  \
95     {                                                                                                      \
96         return static_cast<ClassName&>(META_NS::Object::operator=(other));                                 \
97     }                                                                                                      \
98     ClassName& operator=(ClassName&& other) noexcept                                                       \
99     {                                                                                                      \
100         return static_cast<ClassName&>(META_NS::Object::operator=(static_cast<META_NS::Object&&>(other))); \
101     }
102 
103 /** Caches an interface pointer to InterfaceType with a unique Name identifier */
104 #define META_API_CACHE_INTERFACE(InterfaceType, Name)            \
105 protected:                                                       \
106     InterfaceType* Get##Name##Interface() const noexcept         \
107     {                                                            \
108         return interface_cast<InterfaceType>(this->ObjectRef()); \
109     }
110 
111 /** Returns the interface with given Name cached using META_API_CACHE_INTERFACE */
112 #define META_API_CACHED_INTERFACE(Name) Get##Name##Interface()
113 
114 #define META_API_CALL_INTERFACE(Name, Call)              \
115     [&](auto* intf) {                                    \
116         if (intf) {                                      \
117             return intf->Call;                           \
118         }                                                \
119         using type = decltype(intf->Call);               \
120         if constexpr (!BASE_NS::is_same_v<type, void>) { \
121             return type {};                              \
122         }                                                \
123     }(Get##Name##Interface())
124 
125 /** Defines an implicit conversion to desired interface pointer */
126 #define META_API_OBJECT_CONVERTIBLE(ConvertibleType)                       \
127 public:                                                                    \
128     inline operator ConvertibleType::Ptr() const noexcept                  \
129     {                                                                      \
130         return interface_pointer_cast<ConvertibleType>(this->ObjectRef()); \
131     }                                                                      \
132     inline operator ConvertibleType::ConstPtr() const noexcept             \
133     {                                                                      \
134         return interface_pointer_cast<ConvertibleType>(this->ObjectRef()); \
135     }                                                                      \
136     inline operator ConvertibleType::ConstWeakPtr() const noexcept         \
137     {                                                                      \
138         return interface_pointer_cast<ConvertibleType>(this->ObjectRef()); \
139     }                                                                      \
140     inline operator ConvertibleType::WeakPtr() const noexcept              \
141     {                                                                      \
142         return interface_pointer_cast<ConvertibleType>(this->ObjectRef()); \
143     }                                                                      \
144                                                                            \
145 private:
146 
147 } // namespace Internal
148 
149 /**
150  * @brief The ObjectBase class is the base class for all IObject-derived high level API objects.
151  */
152 class Object {
153     META_API_OBJECT_CONVERTIBLE(META_NS::IMetadata)
154     META_API_CACHE_INTERFACE(META_NS::IMetadata, Metadata)
155     META_API_OBJECT_CONVERTIBLE(META_NS::IAttach)
156     META_API_CACHE_INTERFACE(META_NS::IAttach, Attach)
157 
158 public:
159     Object() = default;
160     virtual ~Object() = default;
161     // Base object accepts any IObject
Object(const Object & other)162     Object(const Object& other) noexcept
163     {
164         SetObjectRef(other);
165     }
Object(Object && other)166     Object(Object&& other) noexcept
167     {
168         SetObjectRef(other);
169         other.ResetIObject();
170     }
Object(const IObject::Ptr & other)171     explicit Object(const IObject::Ptr& other) noexcept
172     {
173         SetObjectRef(other);
174     }
175     /**
176      * @brief Initializes this object with a given IObject::Ptr.
177      * @note Initialize can only be called once on an uninitialized object. Any
178      *       subsequent initialize calls will fail.
179      * @param ptr The IObject::Ptr to initialize from.
180      * @return true if initiazation succeed (class id of ptr matches
181      *         what this object expects), false otherwise.
182      */
Initialize(const META_NS::IObject::Ptr & ptr)183     bool Initialize(const META_NS::IObject::Ptr& ptr)
184     {
185         if (object_) {
186             CORE_LOG_E("%s: Object already initialized. Initialize can only be called on an uninitialized object",
187                 GetClassName().data());
188             return false;
189         }
190         if (IsCompatible(ptr)) {
191             SetObjectRef(ptr);
192             return true;
193         }
194         const BASE_NS::string_view className = ptr ? ptr->GetClassName() : "<null>";
195         CORE_LOG_E("%s: Cannot initialize with an instance of '%s'", GetClassName().data(), className.data());
196         return false;
197     }
198     /**
199      * @brief Resets the underlying IObject::Ptr, effectively returning this object to its
200      *        initial state.
201      */
ResetIObject()202     void ResetIObject()
203     {
204         SetObjectRef({});
205     }
206     /**
207      * @brief Meta::IObject::Ptr conversion operator.
208      */
209     operator const META_NS::IObject::Ptr&() const noexcept
210     {
211         return ObjectRef();
212     }
213     /**
214      * @brief Meta::IObject::ConstPtr conversion operator.
215      */
ConstPtr()216     operator META_NS::IObject::ConstPtr() const noexcept
217     {
218         return ObjectRef();
219     }
220     /**
221      * @brief Meta::IObject::WeakPtr conversion operator.
222      */
WeakPtr()223     operator META_NS::IObject::WeakPtr() const noexcept
224     {
225         return ObjectRef();
226     }
227     /**
228      * @brief Meta::IObject::ConstWeakPtr conversion operator.
229      */
ConstWeakPtr()230     operator META_NS::IObject::ConstWeakPtr() const noexcept
231     {
232         return ObjectRef();
233     }
234     /**
235      * @brief Copy assignment operator
236      */
237     Object& operator=(const Object& other) noexcept
238     {
239         if (IsCompatible(other)) {
240             SetObjectRef(other.ObjectRef());
241         } else {
242             CORE_LOG_E(
243                 "%s: Cannot assign to with an instance of '%s'", GetClassName().data(), other.GetClassName().data());
244         }
245         return *this;
246     }
247     /**
248      * @brief Move assignment operator
249      */
250     Object& operator=(Object&& other) noexcept
251     {
252         if (IsCompatible(other)) {
253             SetObjectRef(other.ObjectRef());
254         } else {
255             ResetIObject();
256             CORE_LOG_E(
257                 "%s: Cannot assign to with an instance of '%s'", GetClassName().data(), other.GetClassName().data());
258         }
259         other.ResetIObject();
260         return *this;
261     }
262     /**
263      * @brief Boolean operator, returns true if the contained object is valid.
264      */
265     explicit operator bool() const noexcept
266     {
267         return object_.operator bool();
268     }
269     /**
270      * @brief Equality operator.
271      * @note Only the underlying object references are compared.
272      */
273     bool operator==(const Object& other) const noexcept
274     {
275         return object_ == other.object_;
276     }
277     /**
278      * @brief Equality operator.
279      * @note Only the underlying object references are compared.
280      */
281     bool operator!=(const Object& other) const noexcept
282     {
283         return !operator==(other);
284     }
285     /**
286      * @brief Return class id of the underlying object
287      */
GetClassId()288     virtual ObjectId GetClassId() const noexcept
289     {
290         return object_ ? object_->GetClassId() : ClassId::Object;
291     }
292     /**
293      * @brief Return class id of the underlying object
294      */
GetClassName()295     virtual BASE_NS::string_view GetClassName() const noexcept
296     {
297         return object_ ? object_->GetClassName() : ClassId::Object.Name();
298     }
299     /**
300      * @brief Returns the contained IObject::Ptr.
301      */
GetIObject()302     inline META_NS::IObject::Ptr GetIObject() const noexcept
303     {
304         return ObjectRef();
305     }
306     /**
307      * @brief Returns true if given object is compatible with this object.
308      * @param ptr The IObject to compare against.
309      */
IsCompatible(const META_NS::IObject::ConstPtr & ptr)310     virtual bool IsCompatible(const META_NS::IObject::ConstPtr& ptr) const noexcept
311     {
312         // Base Object is compatible with any IObject
313         return true;
314     }
315     /**
316      * @brief Returns true if given object is compatible with this object.
317      * @param ptr The Object to compare against.
318      */
IsCompatible(const Object & object)319     virtual bool IsCompatible(const Object& object) const noexcept
320     {
321         return true;
322     }
323     /**
324      * @brief A convenience method for getting an typed interface pointer from a high level API object.
325      * @return
326      */
327     template<class T>
GetInterfacePtr()328     constexpr const typename T::Ptr GetInterfacePtr() const noexcept
329     {
330         return interface_pointer_cast<T>(ObjectRef());
331     }
332     /**
333      * @brief A convenience method for getting an typed interface pointer from a high level API object.
334      * @return
335      */
336     template<class T>
GetInterface()337     constexpr T* GetInterface() const noexcept
338     {
339         return interface_cast<T>(ObjectRef());
340     }
341     /**
342      * @brief Adds a property to the metadata of this object, while enabling
343      *        the builder pattern for object properties.
344      * @param property The property to add.
345      */
MetaProperty(const IProperty::Ptr & property)346     Object& MetaProperty(const IProperty::Ptr& property)
347     {
348         AddProperty(property);
349         return *this;
350     }
351     /**
352      * @brief Adds a property to the metadata of this object.
353      * @param property The property to add.
354      */
AddProperty(const IProperty::Ptr & property)355     void AddProperty(const IProperty::Ptr& property)
356     {
357         META_API_CALL_INTERFACE(Metadata, AddProperty(property));
358     }
359     /**
360      * @brief Removes a property from the metadata of this object.
361      * @param property The property to remove.
362      */
RemoveProperty(const META_NS::IProperty::Ptr & property)363     Object& RemoveProperty(const META_NS::IProperty::Ptr& property)
364     {
365         META_API_CALL_INTERFACE(Metadata, RemoveProperty(property));
366         return *this;
367     }
368     /**
369      * @brief Helper template for adding a property of specific name and value.
370      */
371     template<typename PropertyValueType>
MetaProperty(BASE_NS::string_view propertyName,const PropertyValueType & propertyValue)372     Object& MetaProperty(BASE_NS::string_view propertyName, const PropertyValueType& propertyValue)
373     {
374         if (const auto meta = META_API_CACHED_INTERFACE(Metadata)) {
375             if (const auto existing = meta->GetProperty(propertyName)) {
376                 if (Property<PropertyValueType> typed { existing }) {
377                     typed->SetValue(propertyValue);
378                 } else {
379                     CORE_LOG_E(
380                         "%s: Type mismatch on property '%s'", object_->GetClassName().data(), propertyName.data());
381                 }
382             } else {
383                 meta->AddProperty(ConstructProperty<PropertyValueType>(propertyName, propertyValue));
384             }
385         }
386         return *this;
387     }
388     /**
389      * @brief Helper template for adding an array property of specific name and value.
390      */
391     template<typename PropertyValueType>
ArrayMetaProperty(BASE_NS::string_view propertyName,BASE_NS::array_view<const PropertyValueType> arrayValue)392     Object& ArrayMetaProperty(
393         BASE_NS::string_view propertyName, BASE_NS::array_view<const PropertyValueType> arrayValue)
394     {
395         if (const auto meta = META_API_CACHED_INTERFACE(Metadata)) {
396             if (const auto existing = meta->GetProperty(propertyName)) {
397                 if (auto typed = ArrayProperty<PropertyValueType>(existing)) {
398                     typed->SetValue(arrayValue);
399                 } else {
400                     CORE_LOG_E("%s: Type mismatch on array property '%s'", object_->GetClassName().data(),
401                         propertyName.data());
402                 }
403             } else {
404                 meta->AddProperty(META_NS::ConstructArrayProperty<PropertyValueType>(propertyName, arrayValue));
405             }
406         }
407         return *this;
408     }
409     /**
410      * @brief Returns a reference to the meta data interface of this object.
411      */
Metadata()412     META_NS::IMetadata& Metadata()
413     {
414         return *META_API_CACHED_INTERFACE(Metadata);
415     }
416     /**
417      * @brief Attach an attachment to this object.
418      */
419     auto& Attach(const META_NS::IObject::Ptr& attachment, const META_NS::IObject::Ptr& dataContext = {})
420     {
421         META_API_CALL_INTERFACE(Attach, Attach(attachment, dataContext));
422         return *this;
423     }
424     template<class T, class U>
425     auto& Attach(const T& attachment, const U& dataContext = {})
426     {
427         return Attach(interface_pointer_cast<IObject>(attachment), interface_pointer_cast<IObject>(dataContext));
428     }
429     template<class T>
Attach(const T & attachment)430     auto& Attach(const T& attachment)
431     {
432         return Attach(interface_pointer_cast<IObject>(attachment), {});
433     }
434     /**
435      * @brief Detach an attachment from this object.
436      */
Detach(const META_NS::IObject::Ptr & attachment)437     auto& Detach(const META_NS::IObject::Ptr& attachment)
438     {
439         META_API_CALL_INTERFACE(Attach, Detach(attachment));
440         return *this;
441     }
442     template<class T>
Detach(const T & attachment)443     auto& Detach(const T& attachment)
444     {
445         return Detach(interface_pointer_cast<IObject>(attachment));
446     }
447     /**
448      * @brief Return all attachments matching the constraints.
449      */
450     BASE_NS::vector<META_NS::IObject::Ptr> GetAttachments(const BASE_NS::vector<TypeId>& uids = {}, bool strict = false)
451     {
452         return META_API_CALL_INTERFACE(Attach, GetAttachments(uids, strict));
453     }
454     /**
455      * @brief Return a list of attachments which implement T::UID.
456      */
457     template<class T>
GetAttachments()458     BASE_NS::vector<typename T::Ptr> GetAttachments() const
459     {
460         return META_API_CALL_INTERFACE(Attach, template GetAttachments<T>());
461     }
462 
463 protected:
464     /** Returns a reference to the contained IObject::Ptr */
ObjectRef()465     const META_NS::IObject::Ptr& ObjectRef() const noexcept
466     {
467         if (!object_) {
468             CreateObject();
469         }
470         return object_;
471     }
472     /** Sets the internal object reference */
SetObjectRef(const IObject::Ptr & to)473     void SetObjectRef(const IObject::Ptr& to) const noexcept
474     {
475         if (object_ != to) {
476             object_ = to;
477         }
478     }
479     /** Creates the underlying object, object_ should be valid after this call */
CreateObject()480     virtual void CreateObject() const noexcept
481     {
482         SetObjectRef(META_NS::GetObjectRegistry().Create(ClassId::Object));
483         BASE_ASSERT(object_);
484     }
485 
486 private:
487     mutable META_NS::IObject::Ptr object_;
488 };
489 
490 namespace Internal {
491 
492 template<class FinalClass, const META_NS::ClassInfo& Class>
493 class ObjectInterfaceAPI : public META_NS::Object {
494     using FinalClassType = FinalClass;
495     using Super = Object;
496 
497 public:
498     ObjectInterfaceAPI() = default;
499     ~ObjectInterfaceAPI() override = default;
500     /**
501      * @brief Stores the contained object into a given API class.
502      * @param ptr The target object. The target must be uninitialized.
503      */
Store(FinalClassType & ptr)504     constexpr FinalClassType& Store(FinalClassType& ptr)
505     {
506         auto& me = static_cast<FinalClassType&>(*this);
507         ptr = me;
508         return me;
509     }
510     /**
511      * @brief Returns the class id of the contained object this class supports.
512      */
GetClassId()513     ObjectId GetClassId() const noexcept override
514     {
515         return Class.Id();
516     }
517     /**
518      * @brief Returns the class name of the contained object
519      */
GetClassName()520     BASE_NS::string_view GetClassName() const noexcept override
521     {
522         return Class.Name();
523     }
524     /**
525      * @brief Returns true if this class is compatible with the given class id.
526      * @param id The class id to check against.
527      */
IsCompatible(const ObjectId & id)528     bool IsCompatible(const ObjectId& id) const noexcept
529     {
530         return GetClassId() == id;
531     }
532     /**
533      * @brief See Object::IsCompatible.
534      */
IsCompatible(const META_NS::IObject::ConstPtr & ptr)535     bool IsCompatible(const META_NS::IObject::ConstPtr& ptr) const noexcept override
536     {
537         if (!ptr) {
538             return true;
539         }
540         return GetClassId() == ptr->GetClassId();
541     }
542     /**
543      * @brief See Object::IsCompatible.
544      */
IsCompatible(const Object & object)545     bool IsCompatible(const Object& object) const noexcept override
546     {
547         if (!object) {
548             return true;
549         }
550         return object.GetClassId() == Class.Id();
551     }
552 
553     FinalClassType& Attach(const META_NS::IAttachment::Ptr& attachment, const META_NS::IObject::Ptr& dataContext = {})
554     {
555         Object::Attach(attachment, dataContext);
556         return static_cast<FinalClassType&>(*this);
557     }
Detach(const META_NS::IAttachment::Ptr & attachment)558     FinalClassType& Detach(const META_NS::IAttachment::Ptr& attachment)
559     {
560         Object::Detach(attachment);
561         return static_cast<FinalClassType&>(*this);
562     }
563 
564 protected:
565     /** Creates the contained object */
Create()566     static META_NS::IObject::Ptr Create()
567     {
568         return META_NS::GetObjectRegistry().Create(Class);
569     }
570 
571 private:
CreateObject()572     void CreateObject() const noexcept override
573     {
574         // Make sure that we call the Create method of the derived type,
575         // not necessarily the base implementation.
576         if (const auto object = FinalClassType::Create()) {
577             SetObjectRef(object);
578         } else {
579             CORE_LOG_E("%s: Cannot create instance", Class.Name().data());
580         }
581     }
582 };
583 
584 /** Creates a property forwarder using the interface cached with META_API_CACHE_INTERFACE */
585 #define META_API_INTERFACE_PROPERTY_CACHED(InterfaceCachedName, PropertyName, PropertyType)    \
586     inline META_NS::Property<PropertyType> PropertyName() noexcept                             \
587     {                                                                                          \
588         return META_API_CALL_INTERFACE(InterfaceCachedName, PropertyName());                   \
589     }                                                                                          \
590     inline FinalClassType& PropertyName(const PropertyType& value)                             \
591     {                                                                                          \
592         PropertyName()->SetValue(value);                                                       \
593         return static_cast<FinalClassType&>(*this);                                            \
594     }                                                                                          \
595     inline FinalClassType& PropertyName(const META_NS::IProperty::Ptr& property)               \
596     {                                                                                          \
597         PropertyName()->SetBind(property);                                                     \
598         return static_cast<FinalClassType&>(*this);                                            \
599     }                                                                                          \
600     inline FinalClassType& PropertyName(const META_NS::Property<const PropertyType>& property) \
601     {                                                                                          \
602         PropertyName()->SetBind(property);                                                     \
603         return static_cast<FinalClassType&>(*this);                                            \
604     }                                                                                          \
605     inline FinalClassType& PropertyName(const META_NS::Property<PropertyType>& property)       \
606     {                                                                                          \
607         PropertyName()->SetBind(property);                                                     \
608         return static_cast<FinalClassType&>(*this);                                            \
609     }                                                                                          \
610     inline FinalClassType& PropertyName(const META_NS::IFunction::ConstPtr& function)          \
611     {                                                                                          \
612         PropertyName()->SetBind(function);                                                     \
613         return static_cast<FinalClassType&>(*this);                                            \
614     }                                                                                          \
615     inline FinalClassType& PropertyName(META_NS::Binding&& binding)                            \
616     {                                                                                          \
617         binding.MakeBind(PropertyName());                                                      \
618         return static_cast<FinalClassType&>(*this);                                            \
619     }
620 
621 /** Creates a read-only property forwarder using the interface cached with META_API_CACHE_INTERFACE */
622 #define META_API_INTERFACE_READONLY_PROPERTY_CACHED(InterfaceCachedName, PropertyName, PropertyType) \
623     META_NS::Property<const PropertyType> PropertyName() const                                       \
624     {                                                                                                \
625         return META_API_CALL_INTERFACE(InterfaceCachedName, PropertyName());                         \
626     }
627 
628 /** Creates a property forwarder using the interface cached with META_API_CACHE_INTERFACE */
629 #define META_API_INTERFACE_ARRAY_PROPERTY_CACHED(InterfaceCachedName, PropertyName, PropertyType) \
630     inline META_NS::ArrayProperty<PropertyType> PropertyName() noexcept                           \
631     {                                                                                             \
632         return META_API_CALL_INTERFACE(InterfaceCachedName, PropertyName());                      \
633     }                                                                                             \
634     inline FinalClassType& PropertyName(                                                          \
635         META_NS::ArrayProperty<PropertyType>::IndexType index, const PropertyType& value)         \
636     {                                                                                             \
637         PropertyName()->SetValueAt(index, value);                                                 \
638         return static_cast<FinalClassType&>(*this);                                               \
639     }                                                                                             \
640     inline FinalClassType& PropertyName(const BASE_NS::vector<PropertyType>& value)               \
641     {                                                                                             \
642         PropertyName()->SetValue(value);                                                          \
643         return static_cast<FinalClassType&>(*this);                                               \
644     }                                                                                             \
645     inline FinalClassType& PropertyName(const META_NS::ArrayProperty<PropertyType>& property)     \
646     {                                                                                             \
647         PropertyName()->SetBind(property);                                                        \
648         return static_cast<FinalClassType&>(*this);                                               \
649     }                                                                                             \
650     inline FinalClassType& PropertyName(const META_NS::IFunction::ConstPtr& function)             \
651     {                                                                                             \
652         PropertyName()->SetBind(function);                                                        \
653         return static_cast<FinalClassType&>(*this);                                               \
654     }                                                                                             \
655     inline FinalClassType& PropertyName(META_NS::Binding&& binding)                               \
656     {                                                                                             \
657         binding.MakeBind(PropertyName().GetProperty());                                           \
658         return static_cast<FinalClassType&>(*this);                                               \
659     }
660 
661 /** Creates a property forwarder using the interface cached with META_API_CACHE_INTERFACE */
662 #define META_API_INTERFACE_READONLY_ARRAY_PROPERTY_CACHED(InterfaceCachedName, PropertyName, PropertyType) \
663     META_NS::ArrayProperty<const PropertyType> PropertyName() const                                        \
664     {                                                                                                      \
665         return META_API_CALL_INTERFACE(InterfaceCachedName, PropertyName());                               \
666     }
667 
668 /** Creates a forwarder for a property defined in a specific interface */
669 #define META_API_INTERFACE_PROPERTY(Interface, PropertyName, PropertyType)             \
670     META_NS::Property<PropertyType> PropertyName()                                     \
671     {                                                                                  \
672         auto o = interface_cast<Interface>(ObjectRef());                               \
673         assert(o);                                                                     \
674         return o->PropertyName();                                                      \
675     }                                                                                  \
676     FinalClassType& PropertyName(const PropertyType& value)                            \
677     {                                                                                  \
678         if (auto o = interface_cast<Interface>(ObjectRef())) {                         \
679             o->PropertyName()->SetValue(value);                                        \
680         }                                                                              \
681         return static_cast<FinalClassType&>(*this);                                    \
682     }                                                                                  \
683     FinalClassType& PropertyName(const META_NS::Property<const PropertyType>& binding) \
684     {                                                                                  \
685         if (auto o = interface_cast<Interface>(ObjectRef())) {                         \
686             o->PropertyName()->SetBind(binding);                                       \
687         }                                                                              \
688         return static_cast<FinalClassType&>(*this);                                    \
689     }
690 
691 /** Creates a forwarder for a read-only property defined in a specific interface */
692 #define META_API_INTERFACE_READONLY_PROPERTY(Interface, PropertyName, PropertyType) \
693     const META_NS::Property<const PropertyType> PropertyName() const                \
694     {                                                                               \
695         auto o = interface_cast<Interface>(ObjectRef());                            \
696         assert(o);                                                                  \
697         return o->PropertyName();                                                   \
698     }
699 
700 } // namespace Internal
701 
702 // NOLINTBEGIN(readability-identifier-naming) to keep std like syntax
703 
704 using ::interface_cast;
705 using ::interface_pointer_cast;
706 
707 /**
708  * @brief interface_pointer_cast implementation for high level objects
709  */
710 template<class T>
interface_pointer_cast(const META_NS::Object & object)711 BASE_NS::shared_ptr<T> interface_pointer_cast(const META_NS::Object& object)
712 {
713     static_assert(META_NS::HasGetInterfaceMethod_v<T>, "T::GetInterface not defined");
714     return object.GetInterfacePtr<T>();
715 }
716 
717 /**
718  * @brief interface_cast implementation for high level objects
719  */
720 template<class T>
interface_cast(const META_NS::Object & object)721 T* interface_cast(const META_NS::Object& object)
722 {
723     static_assert(META_NS::HasGetInterfaceMethod_v<T>, "T::GetInterface not defined");
724     return object.GetInterface<T>();
725 }
726 
727 // NOLINTEND(readability-identifier-naming) to keep std like syntax
728 
729 META_END_NAMESPACE()
730 
731 #endif
732