SuperDex Physics C++ API
Loading...
Searching...
No Matches
reflection.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
20
21/**************************************************************************************************
22 * Mochi Reflection
23 *
24 * Mochi uses a first-party C++ reflection library called Simple Reflection. It is rebranded here
25 * using "MOCHI_" prefixed macros, which usually compile out when mochi headers are included
26 * externally.
27 *
28 * Reflection metadata can be used for things like:
29 * - Serialization
30 * - Automatic UI generation
31 * - Portable type identification
32 * - And more...
33 *
34 * Enum Example:
35 *
36 * enum class MyEnum {
37 * Option1,
38 * Option2,
39 * Count
40 * };
41 *
42 * // Then, in the globl namespace:
43 * MOCHI_ENUM_BEGIN(superdex::MyEnum)
44 * MOCHI_ENUM_ITEM(Option1)
45 * MOCHI_ENUM_ITEM(Option2)
46 * MOCHI_ENUM_COUNT(Count)
47 * MOCHI_ENUM_END()
48 *
49 * Struct Example (declared inside the class):
50 *
51 * struct MyStruct {
52 * int someValue = 0;
53 * DynamicArray<Real3> coords;
54 *
55 * MOCHI_STRUCT_BEGIN(superdex::MyStruct)
56 * MOCHI_FIELD(someValue);
57 * MOCHI_FIELD(coords);
58 * MOCHI_STRUCT_END();
59 * };
60 *
61 * Struct Example (declared outside the class):
62 *
63 * struct MyStruct {
64 * int someValue = 0;
65 * DynamicArray<Real3> coords;
66 * };
67 *
68 * // Then, in the global namespace:
69 * MOCHI_STRUCT_BEGIN_EX(superdex::MyStruct)
70 * MOCHI_FIELD(someValue);
71 * MOCHI_FIELD(coords);
72 * MOCHI_STRUCT_END_EX();
73 *
74 * Template Example (internal):
75 *
76 * template <class T, int N>
77 * struct MyTemplate {
78 * std::array<T, N> values;
79 *
80 * MOCHI_TEMPLATE_BEGIN(superdex::Template, T, N)
81 * MOCHI_FIELD(values);
82 * MOCHI_TEMPLATE_END();
83 * };
84 *
85 * Attributes Example (they go AFTER that which they describe):
86 *
87 * MOCHI_STRUCT_BEGIN_EX(superdex::MyStruct)
88 * MOCHI_ATTRIBUTE(Description("This string describes the whole class"));
89 * MOCHI_FIELD(someValue) MOCHI_ATTRIBUTE(ReadOnly);
90 * MOCHI_FIELD(coords) MOCHI_ATTRIBUTE(Units("m"));
91 * MOCHI_STRUCT_END_EX();
92 *
93 */
94
95/**
96 * When MOCHI_USE_REFLECTION is defined to 0, all Mochi reflection macros will compile out. This is
97 * the default so Mochi headers can be included externally without external users taking a
98 * dependency on Simple Reflection. Mochi's build system defins MOCHI_USE_REFLECTION=1 when
99 * compiling Mochi source code, so these features are always available internally.
100 */
101#ifndef MOCHI_USE_REFLECTION
102#define MOCHI_USE_REFLECTION 0
103#endif
104
105#if MOCHI_USE_REFLECTION
106
107#ifdef SIMPLE_REFLECTION_ENABLE
108#if !SIMPLE_REFLECTION_ENABLE
109#error MOCHI_USE_REFLECTION cannot be defined to 1 (true) if SIMPLE_REFLECTION_ENABLE has already been defined to 0 (false).
110#endif
111#else
112#define SIMPLE_REFLECTION_ENABLE 1
113#endif
114
115// Mochi reflection uses only Simple Reflection's picojson/string APIs; the nlohmann::json bridge
116// (SReflect::ToJson/FromJson) is never called. Disabling it keeps the heavy <nlohmann/json.hpp>
117// out of every TU that includes this header. Matches the CMake build (SR_USE_NLOHMANN_JSON=0).
118#ifndef SR_USE_NLOHMANN_JSON
119#define SR_USE_NLOHMANN_JSON 0
120#endif
121
122#ifdef assert_invariant
123#pragma push_macro("assert_invariant")
124#undef assert_invariant
125#define MOCHI_RESTORE_ASSERT_INVARIANT
126#endif
127
128#include <simple_reflection/simple_reflection.h>
129
130#ifdef MOCHI_RESTORE_ASSERT_INVARIANT
131#pragma pop_macro("assert_invariant")
132#undef MOCHI_RESTORE_ASSERT_INVARIANT
133#endif
134
135#define MOCHI_ENUM_BEGIN(name) \
136 IMPL_SR_BeginEnum(name); \
137 [[maybe_unused]] static constexpr int kEnumFirstItemLine = __LINE__ + 1;
138#define MOCHI_ENUM_ITEM(name) IMPL_SR_EnumItem(name)
139#define MOCHI_ENUM_COUNT(name) \
140 static_assert( \
141 static_cast<int>(MyEnum::name) == (__LINE__ - kEnumFirstItemLine), \
142 "Unexpected number of lines in reflection enum definition. Please make sure that every enum value is listed here (one per line).");
143#define MOCHI_ENUM_END() IMPL_SR_EndEnum()
144
145#define MOCHI_STRUCT_BEGIN(name) IMPL_SR_BeginStruct(name, #name)
146#define MOCHI_STRUCT_END() IMPL_SR_EndStruct()
147#define MOCHI_STRUCT(name) MOCHI_STRUCT_BEGIN(name) MOCHI_STRUCT_END()
148#define MOCHI_STRUCT_WITH_BASE(name, base) \
149 MOCHI_STRUCT_BEGIN(name) MOCHI_BASE_CLASS(base) MOCHI_STRUCT_END()
150
151#define MOCHI_STRUCT_BEGIN_EX(name) IMPL_SR_BeginStructEx(name)
152#define MOCHI_STRUCT_END_EX() IMPL_SR_EndStructEx()
153#define MOCHI_STRUCT_EX(name) MOCHI_STRUCT_BEGIN_EX(name) MOCHI_STRUCT_END_EX()
154#define MOCHI_STRUCT_WITH_BASE_EX(name, base) \
155 MOCHI_STRUCT_BEGIN_EX(name) MOCHI_BASE_CLASS(base) MOCHI_STRUCT_END_EX()
156
157#define MOCHI_TEMPLATE_BEGIN(name, ...) IMPL_SR_BeginStructTemplate(name, __VA_ARGS__)
158#define MOCHI_TEMPLATE_END() IMPL_SR_EndStruct()
159#define MOCHI_TEMPLATE(name, ...) MOCHI_TEMPLATE_BEGIN(name, __VA_ARGS__) MOCHI_TEMPLATE_END()
160
161#define MOCHI_FIELD(name) IMPL_SR_Field_Name(name, #name)
162#define MOCHI_FIELD_NAME(realName, customName) IMPL_SR_Field_Name(realName, customName)
163#define MOCHI_REMOVE_FIELD(name) IMPL_SR_RemoveField(name)
164#define MOCHI_REPLACE_FIELD_NAME(realName, fieldNameToReplace) \
165 MOCHI_REMOVE_FIELD(fieldNameToReplace) MOCHI_FIELD_NAME(realName, fieldNameToReplace)
166
167#define MOCHI_BASE_CLASS(name) IMPL_SR_BaseClass(name)
168
169// MOCHI_ATTRIBUTE goes after the thing it describes.
170// See examples in the comment block above.
171#define MOCHI_ATTRIBUTE(...) \
172 { \
173 SReflect::detail::AddAttribute(*myInfo, new ::superdex::attribute::__VA_ARGS__); \
174 }
175
176// MOCHI_ATTRIBUTE_IF adds an attribute conditionally (must be constexpr). Used in templates where
177// the use of the attribute depends on the template parameters.
178#define MOCHI_ATTRIBUTE_IF(condition, ...) \
179 if constexpr (condition) { \
180 MOCHI_ATTRIBUTE(__VA_ARGS__); \
181 }
182
183namespace superdex {
184
185// Base class for all attributes
186using Attribute = SReflect::Attribute;
187
188} // namespace superdex
189
190namespace superdex::attribute {
191
192// [Struct Attribute] Assign a category string to the class/struct, for organization in UI.
193// Example: MOCHI_ATTRIBUTE(Category("text"))
194using Category = SReflect::Attribute_Category;
195
196// [Field Attribute] Marks a 3- or 4-element float field as a linear RGB / RGBA color, so tools can
197// show a color picker rather than numeric drags.
198// Example: MOCHI_ATTRIBUTE(Color)
199using Color = SReflect::Attribute_Color;
200
201// [General Attribute] Add a descriptive string to the struct/field/enum/item.
202// Example: MOCHI_ATTRIBUTE(Description("text"))
203using Description = SReflect::Attribute_Description;
204
205// [General Attribute] Changes how the struct/field/enum/item will appear in UI.
206// Example: MOCHI_ATTRIBUTE(DisplayName("text"))
207using DisplayName = SReflect::Attribute_DisplayName;
208
209// [General Attribute] Do not display the struct/field/enum/item in UI.
210// Example: MOCHI_ATTRIBUTE(HideFromEditor)
211using HideFromEditor = SReflect::Attribute_HideFromEditor;
212
213// [Field Attribute] Indicates that a field should never be serialized/deserialized.
214// Example: MOCHI_ATTRIBUTE(NoSerialize)
215using NoSerialize = SReflect::Attribute_DoNotSerialize;
216
217// [Struct/Field Attribute] Indicates that only fields with non-default values should be serialized.
218// As a field attribute, pass recursive=false to omit the field only when it equals its default,
219// while serializing it in full (all sub-fields shown) when present:
220// MOCHI_ATTRIBUTE(NoSerializeDefaults) // omit defaults, recursing into sub-fields
221// MOCHI_ATTRIBUTE(NoSerializeDefaults(false)) // omit only if the whole field is default
222using NoSerializeDefaults = SReflect::Attribute_DoNotSerializeDefaults;
223
224// [General Attribute] Indicates that something was renamed. Used for backward compatibility.
225// Example: MOCHI_ATTRIBUTE(PreviouslyKnownAs)
226using PreviouslyKnownAs = SReflect::Attribute_PreviouslyKnownAs;
227
228// [Field Attribute] Indicates the legal range of values for a field of signed integer type (any
229// size) Example: MOCHI_ATTRIBUTE(IntRange(-1, 1))
230using IntRange = SReflect::Attribute_IntRange;
231
232// [Field Attribute] Indicates the legal range of values for a field of type float or double.
233// Example: MOCHI_ATTRIBUTE(FloatRange(0_r, 1_r))
234using FloatRange = SReflect::Attribute_FloatRange;
235
236// [Field Attribute] Indicates the legal range of values for a field of unsigned integer type (any
237// size) Example: MOCHI_ATTRIBUTE(UIntRange(0, 1))
238using UIntRange = SReflect::Attribute_UIntRange;
239
240// [Field Attribute] Indicates that the field should appear read-only in tools.
241// Example: MOCHI_ATTRIBUTE(ReadOnly)
242// NOTE: This does not prevent serialization/deserialization.
243using ReadOnly = SReflect::Attribute_ReadOnly;
244
245// [Field Attribute] Indicates the SI unit of measure (short form like "m", "s", "m/s", etc...)
246// Example: MOCHI_ATTRIBUTE(Units("kg"))
247using Units = SReflect::Attribute_Units;
248
249// [Struct Attribute] Suppresses the extraneous-field issue that
250// DeserializeFlags::WarnIfExtraneousFields raises for JSON keys matching no field of this struct.
251// Use for structs that intentionally carry data beyond their reflected schema, so the surrounding
252// document still deserializes strictly. Example: MOCHI_ATTRIBUTE(IgnoreExtraneousFields)
253using IgnoreExtraneousFields = SReflect::Attribute_IgnoreExtraneousFields;
254
255// [Field Attribute] Marks a string field that stores a serialized JSON value: a JSON object/array
256// at this field is stored as its serialized text on load and re-emitted as that JSON value on save
257// (a deserialize/serialize round trip is identity). Applying it to a non-string field fails to
258// deserialize and reports an issue. Example: MOCHI_ATTRIBUTE(JsonString)
259using JsonString = SReflect::Attribute_JsonString;
260
261} // namespace superdex::attribute
262
263#else // if !MOCHI_USE_REFLECTION
264
265// It can be useful to add a semicolon after an attribute because that causes clang-format
266// to keep it on the same line as the thing it modifies. However, the compiler will see this
267// as a stray semicolon within when !MOCHI_USE_REFLECTION. Therefore we suppress the warning
268// within reflection definition blocks.
269#define IMPL_MOCHI_PUSH_IGNORE_EXTRA_SEMI() \
270 MOCHI_WARNING_PUSH() \
271 MOCHI_WARNING_IGNORE_GCC_CLANG(GCC diagnostic ignored "-Wextra-semi")
272
273#define MOCHI_ENUM_BEGIN(name) IMPL_MOCHI_PUSH_IGNORE_EXTRA_SEMI()
274#define MOCHI_ENUM_ITEM(name)
275#define MOCHI_ENUM_COUNT(name)
276#define MOCHI_ENUM_END() MOCHI_WARNING_POP()
277
278#define MOCHI_STRUCT_BEGIN(name) IMPL_MOCHI_PUSH_IGNORE_EXTRA_SEMI()
279#define MOCHI_STRUCT_END() MOCHI_WARNING_POP()
280#define MOCHI_STRUCT(name)
281#define MOCHI_STRUCT_WITH_BASE(name, base)
282
283#define MOCHI_STRUCT_BEGIN_EX(name) IMPL_MOCHI_PUSH_IGNORE_EXTRA_SEMI()
284#define MOCHI_STRUCT_END_EX() MOCHI_WARNING_POP()
285#define MOCHI_STRUCT_EX(name)
286#define MOCHI_STRUCT_WITH_BASE_EX(name, base)
287
288#define MOCHI_TEMPLATE_BEGIN(name, ...)
289#define MOCHI_TEMPLATE_END()
290#define MOCHI_TEMPLATE(name, ...)
291
292#define MOCHI_BASE_CLASS(name)
293#define MOCHI_FIELD(name)
294#define MOCHI_FIELD_NAME(realName, customName)
295#define MOCHI_REMOVE_FIELD(name)
296#define MOCHI_REPLACE_FIELD_NAME(realName, fieldNameToReplace)
297
298#define MOCHI_ATTRIBUTE(...)
299#define MOCHI_ATTRIBUTE_IF(condition, ...)
300
301#endif // !MOCHI_USE_REFLECTION
NdArray< uint8_t, 4 > Color
RGBA color representation using 4 bytes (0-255 per channel) in RGBA order.
Definition color.h:33