1/*
2 * Copyright (C) 2023-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#include <base/containers/type_traits.h>
17#include <base/containers/vector.h>
18#include <base/math/matrix.h>
19#include <base/math/quaternion.h>
20#include <base/math/vector.h>
21#include <base/util/compile_time_hashes.h>
22#include <base/util/uid.h>
23#include <core/ecs/entity.h>
24#include <core/ecs/entity_reference.h>
25#include <core/property/property_types.h>
26
27CORE_BEGIN_NAMESPACE()
28DECLARE_PROPERTY_TYPE(bool);
29DECLARE_PROPERTY_TYPE(char);
30DECLARE_PROPERTY_TYPE(int8_t);
31DECLARE_PROPERTY_TYPE(int16_t);
32DECLARE_PROPERTY_TYPE(int32_t);
33DECLARE_PROPERTY_TYPE(int64_t);
34DECLARE_PROPERTY_TYPE(uint8_t);
35DECLARE_PROPERTY_TYPE(uint16_t);
36DECLARE_PROPERTY_TYPE(uint32_t);
37DECLARE_PROPERTY_TYPE(uint64_t);
38#ifdef __APPLE__
39DECLARE_PROPERTY_TYPE(size_t);
40#endif
41DECLARE_PROPERTY_TYPE(float);
42DECLARE_PROPERTY_TYPE(double);
43
44// The "non-primitive" property declarations should be moved to their respective headers/implementations.
45// (to remove un-necessary "leakage")
46
47DECLARE_PROPERTY_TYPE(BASE_NS::Math::Vec2);
48DECLARE_PROPERTY_TYPE(BASE_NS::Math::Vec3);
49DECLARE_PROPERTY_TYPE(BASE_NS::Math::Vec4);
50DECLARE_PROPERTY_TYPE(BASE_NS::Math::UVec2);
51DECLARE_PROPERTY_TYPE(BASE_NS::Math::UVec3);
52DECLARE_PROPERTY_TYPE(BASE_NS::Math::UVec4);
53DECLARE_PROPERTY_TYPE(BASE_NS::Math::IVec2);
54DECLARE_PROPERTY_TYPE(BASE_NS::Math::IVec3);
55DECLARE_PROPERTY_TYPE(BASE_NS::Math::IVec4);
56DECLARE_PROPERTY_TYPE(BASE_NS::Math::Quat);
57DECLARE_PROPERTY_TYPE(BASE_NS::Math::Mat3X3);
58DECLARE_PROPERTY_TYPE(BASE_NS::Math::Mat4X4);
59DECLARE_PROPERTY_TYPE(BASE_NS::Uid);
60DECLARE_PROPERTY_TYPE(Entity);
61DECLARE_PROPERTY_TYPE(EntityReference);
62DECLARE_PROPERTY_TYPE(BASE_NS::string);
63DECLARE_PROPERTY_TYPE(BASE_NS::vector<float>);
64DECLARE_PROPERTY_TYPE(BASE_NS::vector<Entity>);
65DECLARE_PROPERTY_TYPE(BASE_NS::vector<EntityReference>);
66DECLARE_PROPERTY_TYPE(BASE_NS::vector<BASE_NS::Math::Mat4X4>);
67
68namespace PropertyType {
69// Declare metadatas for some basic types.
70template<class T>
71inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const T*)
72{
73    return {};
74}
75// clang-format off
76template<typename T>
77inline constexpr CORE_NS::ContainerApi vectorArrayMeta{ nullptr, nullptr, nullptr, nullptr, nullptr,
78    { "", 0, CORE_NS::PropertySystem::PropertyTypeDeclFromType<BASE_NS::remove_extent_t<T>, BASE_NS::is_array_t<T>>(),
79        (sizeof(T) / sizeof(BASE_NS::remove_extent_t<T>)), sizeof(T), 0, "", 0,
80        { MetaDataFromType((T*)0), nullptr, {} } } };
81// clang-format on
82
83template<class T>
84inline constexpr const ContainerApi* ContainerApiFromType(const T*)
85{
86    if constexpr (BASE_NS::is_array_v<T>) {
87        return &vectorArrayMeta<BASE_NS::remove_extent_t<T>>;
88    }
89    // non array/vector types
90    return nullptr;
91}
92
93template<class T>
94inline constexpr const ContainerApi* ContainerApiFromType(const BASE_NS::vector<T>*)
95{
96    // vector types..
97    return nullptr;
98}
99
100template<class T>
101inline constexpr CORE_NS::MetaData MetaDataFrom(const T* dummy)
102{
103    return { MetaDataFromType(dummy), ContainerApiFromType(dummy), {} };
104}
105
106// primitive types have no metadata, so just return empty.
107template<>
108inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const bool*)
109{
110    return {};
111}
112template<>
113inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const char*)
114{
115    return {};
116}
117template<>
118inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const int8_t*)
119{
120    return {};
121}
122template<>
123inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const int16_t*)
124{
125    return {};
126}
127template<>
128inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const int32_t*)
129{
130    return {};
131}
132template<>
133inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const int64_t*)
134{
135    return {};
136}
137template<>
138inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const uint8_t*)
139{
140    return {};
141}
142template<>
143inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const uint16_t*)
144{
145    return {};
146}
147template<>
148inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const uint32_t*)
149{
150    return {};
151}
152template<>
153inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const uint64_t*)
154{
155    return {};
156}
157template<>
158inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const float*)
159{
160    return {};
161}
162template<>
163inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const BASE_NS::string*)
164{
165    return {};
166}
167} // namespace PropertyType
168
169// clang-format off
170#define PROPERTYTYPE_GET(b) \
171    CORE_NS::PropertySystem::PropertyTypeDeclFromType<BASE_NS::remove_extent_t<b>, BASE_NS::is_array_t<b>>()
172
173#define BEGIN_PROPERTY(TYPE, NAME) \
174            using COMPTYPE = TYPE; \
175            static constexpr CORE_NS::Property NAME[] = {
176#define DECL_NAMED_PROPERTY_METADATA(structName, prop_name, name, displayname, flags, metadata) \
177    {                                                                                           \
178        #prop_name,                                                                             \
179        BASE_NS::CompileTime::FNV1aHash(#prop_name),                                            \
180        PROPERTYTYPE_GET(BASE_NS::remove_reference_t<decltype(structName::name)>),              \
181        BASE_NS::is_array_v<decltype(structName::name)> ?                                       \
182            BASE_NS::extent_v<BASE_NS::remove_reference_t<decltype(structName::name)>> : 1U,    \
183        sizeof(structName::name), offsetof(structName, name), displayname, (uint32_t)flags,     \
184        metadata                                                                                \
185    },
186#define DECL_NAMED_PROPERTY(structName, prop_name, name, displayname, flags)                             \
187    DECL_NAMED_PROPERTY_METADATA(                                                                        \
188        structName, prop_name, name, displayname, flags,                                                 \
189        CORE_NS::PropertyType::MetaDataFrom((BASE_NS::remove_reference_t<decltype(structName::name)>*)0) \
190    )
191#define DECL_BITFIELD_PROPERTY(structName, name, displayname, flags, enumeration)                     \
192    DECL_NAMED_PROPERTY_METADATA(structName, name, name, displayname, flags,                          \
193        CORE_NS::PropertyType::MetaDataFrom((const enumeration*)0) \
194)
195#define DECL_NAMED_PROPERTY2(prop_name, name, displayname, flags)                                     \
196    DECL_NAMED_PROPERTY(COMPTYPE, prop_name, name, displayname, flags)
197#define DECL_PROPERTY2(structName, name, displayname, flags)                                          \
198    DECL_NAMED_PROPERTY(structName, name, name, displayname, flags)
199#define DECL_PROPERTY3(name, displayname, flags) DECL_PROPERTY2(COMPTYPE, name, displayname, flags)
200#define END_PROPERTY() }
201
202#define BEGIN_METADATA(structName, dataType) \
203    namespace PropertyType { namespace MetaData { inline constexpr CORE_NS::Property MagicData_##structName[] = {
204#define END_METADATA(structName, dataType) }; };  template<>                                             \
205    inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const dataType*)      \
206    {                                                                                                    \
207        return { MetaData::MagicData_##structName, BASE_NS::countof(MetaData::MagicData_##structName) }; \
208    }                                                                                                    \
209    template<>                                                                                           \
210    inline constexpr const ContainerApi* ContainerApiFromType(const dataType*)                           \
211    {                                                                                                    \
212        if constexpr (BASE_NS::is_array_v<dataType>) {return &vectorArrayMeta<dataType>;}                \
213        return nullptr;                                                                                  \
214    }}
215
216#define DECL_ENUM_VALUE(structName, flags)                                                                           \
217    {                                                                                                                \
218        "value", BASE_NS::CompileTime::FNV1aHash("value"), PROPERTYTYPE_GET(BASE_NS::underlying_type_t<structName>), \
219            sizeof(structName), sizeof(structName), 0, "", (uint32_t)flags, {}                                       \
220    }
221
222#define BEGIN_ENUM(structName, dataType)                                                   \
223    namespace PropertyType { namespace MetaData {                                          \
224    inline constexpr Property MagicData_##structName[] = { DECL_ENUM_VALUE(dataType, 0) }; \
225    inline constexpr EnumMetaData MagicEnum_##structName[] = {
226#define DECL_ENUM(dataType, name, displayName) { #name, displayName, (int64_t)dataType::name },
227#define END_ENUM(structName, dataType) }; }; template<>                                                   \
228inline constexpr CORE_NS::MetaData MetaDataFrom(const dataType* /* dummy */)                              \
229{                                                                                                         \
230    return { { MetaData::MagicData_##structName, BASE_NS::countof(MetaData::MagicData_##structName) },    \
231               nullptr,                                                                                   \
232               { MetaData::MagicEnum_##structName, BASE_NS::countof(MetaData::MagicEnum_##structName) }}; \
233}}
234
235// clang-format on
236
237// Declare metadata for these basic types..
238BEGIN_METADATA(UVec2MetaData, BASE_NS::Math::UVec2)
239DECL_PROPERTY2(BASE_NS::Math::UVec2, x, "", 0)
240DECL_PROPERTY2(BASE_NS::Math::UVec2, y, "", 0)
241END_METADATA(UVec2MetaData, BASE_NS::Math::UVec2)
242
243BEGIN_METADATA(UVec3MetaData, BASE_NS::Math::UVec3)
244DECL_PROPERTY2(BASE_NS::Math::UVec3, x, "", 0)
245DECL_PROPERTY2(BASE_NS::Math::UVec3, y, "", 0)
246DECL_PROPERTY2(BASE_NS::Math::UVec3, z, "", 0)
247END_METADATA(UVec3MetaData, BASE_NS::Math::UVec3)
248
249BEGIN_METADATA(UVec4MetaData, BASE_NS::Math::UVec4)
250DECL_PROPERTY2(BASE_NS::Math::UVec4, x, "", 0)
251DECL_PROPERTY2(BASE_NS::Math::UVec4, y, "", 0)
252DECL_PROPERTY2(BASE_NS::Math::UVec4, z, "", 0)
253DECL_PROPERTY2(BASE_NS::Math::UVec4, w, "", 0)
254END_METADATA(UVec4MetaData, BASE_NS::Math::UVec4)
255
256BEGIN_METADATA(IVec2MetaData, BASE_NS::Math::IVec2)
257DECL_PROPERTY2(BASE_NS::Math::IVec2, x, "", 0)
258DECL_PROPERTY2(BASE_NS::Math::IVec2, y, "", 0)
259END_METADATA(IVec2MetaData, BASE_NS::Math::IVec2)
260
261BEGIN_METADATA(IVec3MetaData, BASE_NS::Math::IVec3)
262DECL_PROPERTY2(BASE_NS::Math::IVec3, x, "", 0)
263DECL_PROPERTY2(BASE_NS::Math::IVec3, y, "", 0)
264DECL_PROPERTY2(BASE_NS::Math::IVec3, z, "", 0)
265END_METADATA(IVec3MetaData, BASE_NS::Math::IVec3)
266
267BEGIN_METADATA(IVec4MetaData, BASE_NS::Math::IVec4)
268DECL_PROPERTY2(BASE_NS::Math::IVec4, x, "", 0)
269DECL_PROPERTY2(BASE_NS::Math::IVec4, y, "", 0)
270DECL_PROPERTY2(BASE_NS::Math::IVec4, z, "", 0)
271DECL_PROPERTY2(BASE_NS::Math::IVec4, w, "", 0)
272END_METADATA(IVec4MetaData, BASE_NS::Math::IVec4)
273
274BEGIN_METADATA(Vec2MetaData, BASE_NS::Math::Vec2)
275DECL_PROPERTY2(BASE_NS::Math::Vec2, x, "", 0)
276DECL_PROPERTY2(BASE_NS::Math::Vec2, y, "", 0)
277END_METADATA(Vec2MetaData, BASE_NS::Math::Vec2)
278
279BEGIN_METADATA(Vec3MetaData, BASE_NS::Math::Vec3)
280DECL_PROPERTY2(BASE_NS::Math::Vec3, x, "", 0)
281DECL_PROPERTY2(BASE_NS::Math::Vec3, y, "", 0)
282DECL_PROPERTY2(BASE_NS::Math::Vec3, z, "", 0)
283END_METADATA(Vec3MetaData, BASE_NS::Math::Vec3)
284
285BEGIN_METADATA(Vec4MetaData, BASE_NS::Math::Vec4)
286DECL_PROPERTY2(BASE_NS::Math::Vec4, x, "", 0)
287DECL_PROPERTY2(BASE_NS::Math::Vec4, y, "", 0)
288DECL_PROPERTY2(BASE_NS::Math::Vec4, z, "", 0)
289DECL_PROPERTY2(BASE_NS::Math::Vec4, w, "", 0)
290END_METADATA(Vec4MetaData, BASE_NS::Math::Vec4)
291
292BEGIN_METADATA(QuatMetaData, BASE_NS::Math::Quat)
293DECL_PROPERTY2(BASE_NS::Math::Quat, x, "", 0)
294DECL_PROPERTY2(BASE_NS::Math::Quat, y, "", 0)
295DECL_PROPERTY2(BASE_NS::Math::Quat, z, "", 0)
296DECL_PROPERTY2(BASE_NS::Math::Quat, w, "", 0)
297END_METADATA(QuatMetaData, BASE_NS::Math::Quat)
298
299BEGIN_METADATA(Mat3x3MetaData, BASE_NS::Math::Mat3X3)
300DECL_PROPERTY2(BASE_NS::Math::Mat3X3, data, "", 0)
301END_METADATA(Mat3x3MetaData, BASE_NS::Math::Mat3X3)
302
303BEGIN_METADATA(Mat4x4MetaData, BASE_NS::Math::Mat4X4)
304DECL_PROPERTY2(BASE_NS::Math::Mat4X4, data, "", 0)
305END_METADATA(Mat4x4MetaData, BASE_NS::Math::Mat4X4)
306
307BEGIN_METADATA(EntityMetaData, Entity)
308DECL_PROPERTY2(Entity, id, "", 0)
309END_METADATA(EntityMetaData, Entity)
310
311BEGIN_METADATA(UIDMetaData, BASE_NS::Uid)
312DECL_PROPERTY2(BASE_NS::Uid, data, "", 0)
313END_METADATA(UIDMetaData, BASE_NS::Uid)
314
315// helpers for "vector" containers.
316namespace PropertyType {
317template<typename T>
318size_t size(uintptr_t container)
319{
320    auto& vec = *(BASE_NS::vector<T>*)(container);
321    return vec.size();
322}
323template<typename T>
324void resize(uintptr_t container, size_t newsize)
325{
326    auto& vec = *(BASE_NS::vector<T>*)(container);
327    vec.resize(newsize);
328}
329
330template<typename T>
331void erase(uintptr_t container, size_t index)
332{
333    auto& vec = *(BASE_NS::vector<T>*)(container);
334    vec.erase(vec.begin() + static_cast<typename BASE_NS::vector<T>::difference_type>(index));
335}
336template<typename T>
337uintptr_t insert(uintptr_t container, size_t index)
338{
339    auto& vec = *(BASE_NS::vector<T>*)(container);
340    vec.insert(vec.begin() + static_cast<typename BASE_NS::vector<T>::difference_type>(index), {});
341    return (uintptr_t)&vec[index];
342}
343
344template<typename T>
345uintptr_t get(uintptr_t container, size_t index)
346{
347    auto& vec = *(BASE_NS::vector<T>*)(container);
348    return (uintptr_t)&vec[index];
349}
350
351template<class T>
352inline constexpr CORE_NS::MetaData MetaDataFromT { MetaDataFromType((T*)nullptr), ContainerApiFromType((T*)nullptr),
353    {} };
354
355template<typename T>
356inline constexpr CORE_NS::Property containerElementProperty { "", 0,
357    CORE_NS::PropertySystem::PropertyTypeDeclFromType<BASE_NS::remove_extent_t<T>, BASE_NS::is_array_t<T>>(),
358    (sizeof(T) / sizeof(BASE_NS::remove_extent_t<T>)), sizeof(T), 0, "", 0,
359    MetaDataFromT<BASE_NS::remove_extent_t<T>> };
360
361template<typename T>
362inline constexpr CORE_NS::ContainerApi data { size<T>, resize<T>, erase<T>, insert<T>, get<T>,
363    containerElementProperty<T> };
364} // namespace PropertyType
365
366#define DECLARE_CONTAINER_API(blob, type)                                                                        \
367    namespace PropertyType {                                                                                     \
368    template<>                                                                                                   \
369    inline constexpr const ContainerApi* ContainerApiFromType(const BASE_NS::vector<type>*)                      \
370    {                                                                                                            \
371        return &data<type>;                                                                                      \
372    }                                                                                                            \
373    template<>                                                                                                   \
374    inline constexpr BASE_NS::array_view<const CORE_NS::Property> MetaDataFromType(const BASE_NS::vector<type>*) \
375    {                                                                                                            \
376        return {};                                                                                               \
377    }                                                                                                            \
378    }
379
380// Declare vector style container for these primitive types.
381DECLARE_CONTAINER_API(uint8_t, uint8_t);
382DECLARE_CONTAINER_API(uint16_t, uint16_t);
383DECLARE_CONTAINER_API(uint32_t, uint32_t);
384DECLARE_CONTAINER_API(MathVec4, BASE_NS::Math::Vec4);
385DECLARE_CONTAINER_API(MathMath4X4, BASE_NS::Math::Mat4X4);
386DECLARE_CONTAINER_API(float, float);
387DECLARE_CONTAINER_API(string, BASE_NS::string);
388DECLARE_CONTAINER_API(Entity, Entity);
389DECLARE_CONTAINER_API(EntityReference, EntityReference);
390
391CORE_END_NAMESPACE()
392