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_EXT_METADATA_HELPERS_H
17 #define META_EXT_METADATA_HELPERS_H
18 
19 #include <meta/interface/intf_metadata.h>
20 #include <meta/interface/intf_object.h>
21 #include <meta/interface/property/intf_property_internal.h>
22 #include <meta/interface/static_object_metadata.h>
23 
META_BEGIN_NAMESPACE()24 META_BEGIN_NAMESPACE()
25 
26 /**
27  * @brief Helper to construct/add properties to newly created object using the static metadata.
28  */
29 template<typename Self>
30 void ConstructPropertiesFromMetadata(Self* self, const StaticObjectMetadata& sm, const IMetadata::Ptr& meta)
31 {
32     for (auto&& pm : sm.properties) {
33         auto p = meta->GetPropertyByName(pm.name);
34         if (p) {
35             if (!pm.init(self, p)) {
36                 p = nullptr;
37             }
38         }
39         if (!p) {
40             p = pm.create();
41             if (!pm.init(self, p)) {
42                 CORE_ASSERT_MSG(false, "Failed to initialise property");
43                 return;
44             }
45             meta->AddProperty(p);
46         }
47         if (auto pp = interface_cast<IPropertyInternal>(p)) {
48             if (auto s = self->GetInterface(IObjectInstance::UID)) {
49                 pp->SetOwner(static_cast<IObjectInstance*>(s)->GetSelf());
50             }
51         }
52     }
53 }
54 
55 /**
56  * @brief Helper to construct or init event.
57  */
58 template<typename Self>
ConstructOrInitEvent(IEvent::Ptr & p,Self * self,const EventMetadata & pm)59 bool ConstructOrInitEvent(IEvent::Ptr& p, Self* self, const EventMetadata& pm)
60 {
61     if (p) {
62         if (!pm.init(self, p)) {
63             p = nullptr;
64         }
65     }
66     if (!p) {
67         p = pm.create();
68         if (!pm.init(self, p)) {
69             CORE_ASSERT_MSG(false, "Failed to initialise event");
70             return false;
71         }
72         return true;
73     }
74     return false;
75 }
76 
77 /**
78  * @brief Helper to construct/add events to newly created object using the static metadata.
79  */
80 template<typename Self>
ConstructEventsFromMetadata(Self * self,const StaticObjectMetadata & sm,const IMetadata::Ptr & meta)81 void ConstructEventsFromMetadata(Self* self, const StaticObjectMetadata& sm, const IMetadata::Ptr& meta)
82 {
83     for (auto&& pm : sm.events) {
84         auto p = meta->GetEventByName(pm.name);
85         if (ConstructOrInitEvent(p, self, pm)) {
86             meta->AddEvent(p);
87         }
88     }
89 }
90 
91 /**
92  * @brief Helper to construct/add meta functions to newly created object using the static metadata.
93  */
94 template<typename Self>
ConstructFunctionsFromMetadata(Self * self,const StaticObjectMetadata & sm,const IMetadata::Ptr & meta)95 void ConstructFunctionsFromMetadata(Self* self, const StaticObjectMetadata& sm, const IMetadata::Ptr& meta)
96 {
97     for (auto&& pm : sm.functions) {
98         auto p = pm.create(self);
99         if (!p) {
100             CORE_ASSERT_MSG(false, "Failed to create function");
101             return;
102         }
103         meta->AddFunction(p);
104     }
105 }
106 
107 /**
108  * @brief Add static metadata machinery to object. This is usually done by ObjectFwd and a like helpers.
109  */
110 #define STATIC_METADATA_MACHINERY(classinfo, baseclass)                                                              \
111     using Impl = baseclass;                                                                                          \
112                                                                                                                      \
113 protected:                                                                                                           \
114     bool IsFirstInit()                                                                                               \
115     {                                                                                                                \
116         static bool init = (isFirstInit_ = true);                                                                    \
117         return isFirstInit_;                                                                                         \
118     }                                                                                                                \
119     template<typename Type>                                                                                          \
120     META_NS::nullptr_t RegisterStaticPropertyMetadata(const META_NS::InterfaceInfo& intf, BASE_NS::string_view name, \
121         META_NS::ObjectFlagBitsValue flags, META_NS::Internal::PCtor* ctor, META_NS::Internal::PMemberInit* init)    \
122     {                                                                                                                \
123         if (IsFirstInit()) {                                                                                         \
124             StaticObjectMeta().properties.push_back(                                                                 \
125                 META_NS::PropertyMetadata { name, intf, flags, META_NS::UidFromType<Type>(), ctor, init });          \
126         }                                                                                                            \
127         return nullptr;                                                                                              \
128     }                                                                                                                \
129     template<typename Type>                                                                                          \
130     META_NS::nullptr_t RegisterStaticEventMetadata(const META_NS::InterfaceInfo& intf, BASE_NS::string_view name,    \
131         META_NS::Internal::ECtor* ctor, META_NS::Internal::EMemberInit* init)                                        \
132     {                                                                                                                \
133         if (IsFirstInit()) {                                                                                         \
134             StaticObjectMeta().events.push_back(META_NS::EventMetadata { name, intf, Type::UID, ctor, init });       \
135         }                                                                                                            \
136         return nullptr;                                                                                              \
137     }                                                                                                                \
138     META_NS::nullptr_t RegisterStaticFunctionMetadata(const META_NS::InterfaceInfo& intf, BASE_NS::string_view name, \
139         META_NS::Internal::FCtor* ctor, META_NS::Internal::FContext* context)                                        \
140     {                                                                                                                \
141         if (IsFirstInit()) {                                                                                         \
142             StaticObjectMeta().functions.push_back(META_NS::FunctionMetadata { name, intf, ctor, context });         \
143         }                                                                                                            \
144         return nullptr;                                                                                              \
145     }                                                                                                                \
146                                                                                                                      \
147 private:                                                                                                             \
148     bool isFirstInit_ {};                                                                                            \
149     static META_NS::StaticObjectMetadata& StaticObjectMeta()                                                         \
150     {                                                                                                                \
151         static META_NS::StaticObjectMetadata meta { classinfo, &Impl::GetStaticObjectMetadata() };                   \
152         return meta;                                                                                                 \
153     }                                                                                                                \
154                                                                                                                      \
155 public:                                                                                                              \
156     static const META_NS::StaticObjectMetadata& GetStaticObjectMetadata()                                            \
157     {                                                                                                                \
158         return StaticObjectMeta();                                                                                   \
159     }                                                                                                                \
160                                                                                                                      \
161 private:
162 
163 #define STATIC_METADATA_MACHINERY_WITH_CONCRETE_BASE(classinfo, baseclass)        \
164     STATIC_METADATA_MACHINERY(classinfo, baseclass)                               \
165 protected:                                                                        \
166     const META_NS::StaticObjectMetadata& GetStaticMetadata() const override       \
167     {                                                                             \
168         return GetStaticObjectMetadata();                                         \
169     }                                                                             \
170     void SetMetadata(const META_NS::IMetadata::Ptr& meta) override                \
171     {                                                                             \
172         Impl::SetMetadata(meta);                                                  \
173         META_NS::ConstructPropertiesFromMetadata(this, StaticObjectMeta(), meta); \
174         META_NS::ConstructEventsFromMetadata(this, StaticObjectMeta(), meta);     \
175         META_NS::ConstructFunctionsFromMetadata(this, StaticObjectMeta(), meta);  \
176     }
177 
178 #define STATIC_METADATA_WITH_CONCRETE_BASE(introduced, baseclass) \
179     STATIC_METADATA_MACHINERY_WITH_CONCRETE_BASE(ClassInfo, baseclass)
180 
181 META_END_NAMESPACE()
182 
183 #endif
184