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