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