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